home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v8n16.arc / DIRMATCH.ASM < prev    next >
Assembly Source File  |  1989-08-30  |  97KB  |  1,919 lines

  1. ;-----------------------------------------------------------------------------;
  2. ;  DIRMATCH * PC Magazine * Michael J. Mefford                                 ;
  3. ;  Points out the similarity and differences of two directories and then       ;
  4. ;  lets you update the target directory with specific source directory files.  ;
  5. ;-----------------------------------------------------------------------------;
  6. _TEXT          SEGMENT PUBLIC 'CODE'
  7.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  8.                ORG     100H
  9. START:         JMP     MAIN
  10.  
  11. ;              DATA AREA
  12. ;              ---------
  13. SIGNATURE      DB      CR,SPACE,SPACE,SPACE,CR,LF
  14. COPYRIGHT      DB      "DIRMATCH 1.0 (C) 1989 Ziff Communications Co. ",CR,LF
  15. PROGRAMMER     DB      "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  16.  
  17. DB             "Syntax:  DIRMATCH source target [/D][/A]",CR,LF,LF
  18. DB             "/D = Different files",CR,LF
  19. DB             "/A = Alike files$",CTRL_Z
  20.  
  21. TAB            EQU     9
  22. CR             EQU     13
  23. LF             EQU     10
  24. CTRL_Z         EQU     26
  25. SPACE          EQU     32
  26. BOX            EQU     254
  27. VERT_LINE      EQU     179
  28. FF             EQU     12
  29. SHIFT_KEYS     EQU     3
  30. LITTLE_ARROW   EQU     26
  31. ESC_SCAN       EQU     1
  32. Y_SCAN         EQU     15H
  33. N_SCAN         EQU     31H
  34. NOTE           EQU     1046                    ; C
  35. SPEC_LENGTH    EQU     66 + 12
  36.  
  37. MENU           LABEL BYTE
  38. DB "F1 ",0, "All files  ",0, "Different files  ",0, "Alike files  ",0
  39. DB "F2 Mark all  F3 Clear marks  F4 CopyF5 Move   F6 Print   "
  40. DB "Use: ",24,32,25," PgUp PgDn Home End   +/- Mark/Unmark   Esc to Exit",0
  41.  
  42. ALL            EQU     0
  43. UNIQUE         EQU     2
  44. ALIKE          EQU     4
  45.  
  46. FILES_MODE     DB      ALL
  47. MODES          DW      DO_ALL, DO_UNIQUE, DO_ALIKE
  48.  
  49. CRT_MODE       EQU     49H
  50. CRT_ROWS       EQU     84H
  51. STATUS_REG     DW      3BAH
  52. VIDEO_SEG      DW      0B000H
  53. ROWS           DB      24
  54. SYNTAX_FLAG    DB      0
  55.  
  56. HEADING_ATTR   DB      70H
  57. ACTIVE_ATTR    DB      0FH
  58. BODY_ATTR      DB      07H
  59. HIGHLIGHT_ATTR DB      0FH
  60. MENU_ATTR      DB      07H
  61. BAR_ATTR       DB      70H
  62. INTENSE        EQU     7FH
  63. INTENSE_BLUE   EQU     1FH
  64. BLUE           EQU     17H
  65. INVERSE_BLUE   EQU     71H
  66. CYAN           EQU     31H
  67.  
  68. TOP_MEMORY     DW      ?
  69. DEFAULT_DRIVE  DB      ?
  70. SOURCE_SEG     DW      ?
  71. TARGET_SEG     DW      ?
  72. BUFFER_SEG     DW      ?
  73. BUFFER_SIZE    DW      0FFFFH
  74. SOURCE_END     DW      ?
  75. TARGET_END     DW      ?
  76. LISTING_LINE   DW      0
  77. BAR_LINE       DW      0
  78. LAST_BAR       DW      ?
  79. PAGE_LENGTH    DW      ?
  80. SOURCE_COUNT   DW      ?
  81. TARGET_COUNT   DW      ?
  82. MARKED_COUNT   DW      ?
  83. RESPONSE       DW      ?
  84.  
  85. OUT_OF_MEMORY  DB      "Not enough memory ",0,"$"
  86. TOO_MANY       DB      "Too many files ",0,"$"
  87. SOURCE_PROMPT  DB      CR,LF,LF,"Source$"
  88. TARGET_PROMPT  DB      CR,LF,LF,"Target$"
  89. NOT_FOUND      DB      " filespec not found",CR,LF
  90.                DB      "Enter filespec: $"
  91.  
  92. PRESS_MSG      DB      "Error; Press any key",0
  93. SOURCE_MSG     DB      " Source",0
  94. DIRECTORY_MSG  DB      " Directory",0
  95. FILES_MSG      DB      " files",0
  96. GAP            EQU     4
  97. DIRECTORY_LEN  EQU     $ - SOURCE_MSG + GAP - 3
  98. TO_MSG         DB      " to"
  99. TARGET_MSG     DB      " Target",0
  100. COPY_MSG       DB      "Copy ",0
  101. MOVE_MSG       DB      "Move ",0
  102. MARKED_MSG     DB      " marked files",0
  103. QUERY_MSG      DB      "?  Y/N ",0
  104. STAR_DOT_STAR  DB      "*.*",0
  105.  
  106. RECENT         DB      ">",   6 DUP (?)
  107. NOT_RECENT     DB      SPACE, 6 DUP (?)
  108.  
  109. DISPATCH_KEY   DB      48H,   50H,   49H,   51H,   47H,   4FH
  110.                DB      3BH,   54H,   3CH,   3DH,   3EH,   3FH
  111.                DB      40H,   01H,   0DH,   4EH,   0CH,   4AH
  112. DISPATCH_CNT   EQU     $ - DISPATCH_KEY
  113.  
  114. DISPATCH_TABLE DW      UP,    DOWN,  PGUP,  PGDN,  HOME,  END_KEY
  115.                DW      F1,    S_F1,  F2,    F3,    F4,    F5
  116.                DW      F6,    EXIT,  PLUS,  PLUS,  MINUS, MINUS
  117. DISPATCH_END   EQU     $ - 2
  118.  
  119. MATCHING       STRUC
  120. RESERVED       DB      21 DUP (?)
  121. ATTRIBUTE      DB              ?
  122. FILE_TIME      DW              ?
  123. FILE_DATE      DW              ?
  124. SIZE_LOW       DW              ?
  125. SIZE_HIGH      DW              ?
  126. FILE_NAME      DB      13 DUP (?)
  127. MATCHING       ENDS
  128.  
  129. FILE_RECORD    STRUC
  130. LIST_NAME      DB      12 DUP (?)
  131. LIST_BYTES     DB       9 DUP (?)
  132. LIST_DATE      DB      10 DUP (?)
  133. LIST_TIME      DB       8 DUP (?)
  134. MARK           DB              ?
  135. DOS_DATE       DW              ?
  136. DOS_TIME       DW              ?
  137. DISP_ORDER     DW              ?
  138. FILE_RECORD    ENDS
  139.  
  140. ;              CODE AREA
  141. ;              ---------
  142. MAIN           PROC    NEAR
  143.                CLD                             ;String instructions forward.
  144.                MOV     BX,0FFFFH               ;Memory allocation request will
  145.                MOV     AH,4AH                  ; fail and BX will return with
  146.                INT     21H                     ; available memory in 
  147.                                                ; paragraphs.
  148.                CMP     BX,64 * (1024 / 16)     ;At least 64K paragraphs?
  149.                JAE     ALLOCATE
  150.                MOV     DX,OFFSET OUT_OF_MEMORY
  151.                JMP     ERROR_EXIT              ;If no, exit.
  152. ALLOCATE:      MOV     AH,4AH                  ;Else, allocate all available.
  153.                INT     21H
  154.                MOV     AX,DS                   ;Get our segment;
  155.                ADD     AX,BX                   ; add to available and save
  156.                MOV     TOP_MEMORY,AX           ; as segment of memory top.
  157.  
  158.                MOV     SP,OFFSET STACK_POINTER ;Set up stack.
  159.  
  160.                MOV     DX,OFFSET DTA           ;Set up Disk Transfer Address.
  161.                MOV     AH,1AH
  162.                INT     21H
  163.  
  164.                MOV     AH,19H                  ;Get default drive so can
  165.                INT     21H                     ; restore after we change it.
  166.                MOV     DEFAULT_DRIVE,AL
  167.  
  168. ;----------------------------------------------;
  169. CK_SWITCH:     MOV     SI,81H                  ;Point to command line.
  170. NEXT_SWITCH:   LODSB                           ;Get a byte.
  171.                CMP     AL,CR                   ;Is it carriage return?
  172.                JZ      PARSE_SOURCE            ;If yes, done here.
  173.                CMP     AL,"/"                  ;Is it switch delimiter?
  174.                JNZ     NEXT_SWITCH             ;If no, next byte.
  175.                LODSB                           ;Get the switch character.
  176.                CMP     AL,CR                   ;Make sure it's not CR
  177.                JZ      PARSE_SOURCE            ; so we don't go past end.
  178.                AND     AL,5FH                  ;Capitalize.
  179. CK_UNIQUE:     CMP     AL,"D"                  ;If "D", then Different files.
  180.                JNZ     CK_ALIKE
  181.                MOV     FILES_MODE,UNIQUE
  182. CK_ALIKE:      CMP     AL,"A"                  ;If "A", then Alike files.
  183.                JNZ     NEXT_SWITCH             ;If none of these, next byte.
  184.                MOV     FILES_MODE,ALIKE
  185.                JMP     NEXT_SWITCH
  186.  
  187. ;---------------------------------------------------------------;
  188. ; Parse the command line for filespecs.  If one or both missing ;
  189. ; or file can't be opened, prompt the user for filespec.        ;
  190. ;---------------------------------------------------------------;
  191. PARSE_SOURCE:  MOV     SI,81H                  ;Point to command line again.
  192.                CALL    PARSE_SPEC              ;Parse a filespec.
  193.                PUSH    [SI]                    ;Save ending byte
  194.                PUSH    SI                      ; and the pointer.
  195.                JNZ     SOURCE_PATH             ;If filespec found, check path.
  196. PROMPT1:       XOR     DI,DI                   ;Else, ask user for first
  197.                CALL    PROMPT_USER             ; filespec.
  198.                CALL    PARSE_SPEC              ;Parse it.
  199.                JZ      PROMPT1                 ;If null string, prompt again.
  200. SOURCE_PATH:   MOV     DI,OFFSET SOURCE_SPEC   ;Storage for complete filespec.
  201.                CALL    FIND_PATH               ;Parse the path from filespec.
  202.                JC      PROMPT1                 ;If not found, prompt user.
  203.                MOV     SOURCE_END,SI           ;Else, store source path end.
  204.                MOV     BP,ES                   ;Calculate the segment to save
  205.                MOV     DI,OFFSET SOURCE_OFFSET ; first batch of filenames.
  206.                CALL    CALC_SEG
  207.                MOV     SOURCE_SEG,BP           ;Save it.
  208.                CALL    SOURCE_DIR
  209.                JC      ERROR_EXIT              ;If ran out of memory, exit.
  210.                POP     SI                      ;Recover command line pointer
  211.                POP     [SI]                    ; and restore string
  212.                                                ; terminator.
  213.  
  214. PARSE_TARGET:  CALL    PARSE_SPEC              ;Parse for second filespec.
  215.                JNZ     TARGET_PATH             ;If not null string, check
  216.                                                ; path.
  217. PROMPT2:       MOV     DI,1                    ;Else, prompt user for second
  218.                CALL    PROMPT_USER             ; filespec and then parse it.
  219.                JMP     PARSE_TARGET
  220. TARGET_PATH:   MOV     DI,OFFSET TARGET_SPEC   ;Storage for complete filespec.
  221.                CALL    FIND_PATH               ;Parse path from filespec.
  222.                JC      PROMPT2                 ;If not found, prompt user.
  223.                MOV     TARGET_END,SI           ;Else, save target path end.
  224.                CALL    TARGET_DIR              ;Get target files.
  225.                JC      ERROR_EXIT
  226.  
  227. DO_SETUP:      CALL    VIDEO_SETUP             ;Prepare for video environment.
  228.                CALL    MATCH                   ;Match the filenames.
  229.  
  230. ;----------------------------------------------------------;
  231. ; Loop here processing user commands and updating display. ;
  232. ;----------------------------------------------------------;
  233. INPUT:         CALL    DISP_LISTINGS           ;Update the display.
  234.                CALL    GET_KEY
  235.                MOV     DI,OFFSET DISPATCH_KEY  ;Check dispatch table.
  236.                MOV     CX,DISPATCH_CNT
  237.                REPNZ   SCASB
  238.                JNZ     INPUT                   ;If no match, ignore.
  239.                SHL     CX,1                    ;Else, look up subroutine
  240.                MOV     DI,OFFSET DISPATCH_END
  241.                SUB     DI,CX
  242.                MOV     BP,BAR_LINE             ;Paging commands need line
  243.                MOV     BX,LISTING_LINE         ; page data.
  244.                MOV     CX,LAST_BAR
  245.                MOV     DX,PAGE_LENGTH
  246.                CALL    [DI]                    ;Process the command.
  247.                JMP     INPUT                   ;Next input.
  248.  
  249. ;----------------------------------------------;
  250. ERROR_EXIT:    CALL    PRINT_STRING            ;Print error message.
  251. ERROR:         MOV     AL,1                    ;Exit with ERRORLEVEL one.
  252.                JMP     SHORT TERMINATE
  253.  
  254. EXIT:          MOV     DH,ROWS                 ;Clear last two lines.
  255.                MOV     CH,DH
  256.                DEC     CH
  257.                XOR     CL,CL
  258.                MOV     DL,80 - 1
  259.                MOV     BH,MENU_ATTR
  260.                MOV     AX,600H                 ; by scrolling active page.
  261.                INT     10H
  262.  
  263.                XOR     BX,BX                   ;Border back to black.
  264.                MOV     AH,0BH
  265.                INT     10H
  266.  
  267.                MOV     DH,CH                   ;Place cursor on next
  268.                DEC     DH                      ; to last line.
  269.                XOR     DL,DL
  270.                CALL    SET_CURSOR
  271.                XOR     AL,AL                   ;ERRORLEVEL zero.
  272. TERMINATE:     MOV     AH,4CH                  ;Terminate.
  273.                INT     21H
  274. MAIN           ENDP
  275.  
  276. ;              ***************
  277. ;              * SUBROUTINES *
  278. ;              ***************
  279. ;-------------------------------------------------;
  280. SOURCE_DIR:    MOV     BP,SOURCE_SEG
  281.                MOV     DX,OFFSET SOURCE_SPEC
  282.                CALL    FIND_FILES              ;Find the filenames.
  283.                JC      GET_END1
  284.                CALL    CALC_SEG                ;If successful, calculate
  285.                                                ; segment of target DIR
  286.                MOV     TARGET_SEG,BP           ; filename storage.
  287.                CLC
  288. GET_END1:      RET
  289.  
  290. ;-------------------------------------------------;
  291. ; OUTPUT: CY = 1 if failed;  DX -> Error message. ;
  292. ;-------------------------------------------------;
  293. TARGET_DIR:    MOV     BP,TARGET_SEG           ;Retrieve segment for
  294.                                                ; filenames.
  295.                MOV     DX,OFFSET TARGET_SPEC
  296.                CALL    FIND_FILES              ;Find the filenames.
  297.                JC      GET_END2                ;If ran out of memory, exit.
  298.                CALL    CALC_SEG                ;If successful, calculate
  299.                MOV     BUFFER_SEG,BP           ; segment of copy buffer.
  300.                MOV     AX,TOP_MEMORY           ;Retrieve top of memory 
  301.                                                ; segment.
  302.                SUB     AX,BP                   ;Paragraphs available for
  303.                                                ; buffer.
  304.                MOV     DX,OFFSET OUT_OF_MEMORY
  305.                JBE     GET_END2                ;If none, exit.
  306.                CMP     AX,80H                  ;If less than practical minimum
  307.                JB      GET_END2                ; of 2K bytes (128 para), exit.
  308.                CMP     AX,1000H                ;If more than 4K paragraphs
  309.                JAE     GET_END2                ; (64K bytes), then use
  310.                                                ; default.
  311.                MOV     CL,4                    ;Else, convert paragraphs to
  312.                SHL     AX,CL                   ; bytes and save as buffer
  313.                MOV     BUFFER_SIZE,AX          ; size.
  314.                CLC
  315. GET_END2:      RET
  316.  
  317. ;----------------------------------------------;
  318. MATCH:         MOV     BAR_LINE,0
  319.                MOV     LISTING_LINE,0          ;Move listing to top.
  320. DO_MATCH:      PUSH    DS                      ;Preserve segments.
  321.                PUSH    ES
  322.                MOV     SOURCE_COUNT,0
  323.                MOV     TARGET_COUNT,0          ;Initialize file counts to
  324.                                                ; zero.
  325.  
  326.                MOV     DL,FILES_MODE           ;Get offset of current
  327.                XOR     DH,DH                   ; file display mode.
  328.                ADD     DX,OFFSET MODES
  329.                MOV     ES,TARGET_SEG           ;Target listing segment.
  330.                MOV     DS,SOURCE_SEG           ;Source listing segment.
  331.                XOR     BX,BX                   ;DS:BX -> source.
  332.                XOR     BP,BP                   ;ES:BP -> target.
  333.                XOR     AX,AX                   ;Counter.
  334. NEXT_MATCH:    CMP     BYTE PTR ES:LIST_NAME[BP],-1   ;End of listing 2?
  335.                JNZ     COMPARE                        ;If no, compare
  336.                                                       ; filenames.
  337.                CMP     BYTE PTR LIST_NAME[BX],-1      ;Else, end of listing 1?
  338.                JZ      MATCH_END                      ;If yes, done here.
  339.  
  340. COMPARE:       MOV     SI,BX                   ;Get pointers to filenames.
  341.                MOV     DI,BP
  342.                MOV     CX,SIZE LIST_NAME
  343.                REP     CMPSB                   ;Compare the names.
  344.                MOV     DI,DX
  345.                CALL    CS:[DI]                 ;Process.
  346.                JMP     NEXT_MATCH              ;Do next match.
  347.  
  348. MATCH_END:     POP     ES                      ;Restore segments.
  349.                POP     DS
  350.                DEC     AX                      ;Adjust counter.
  351.                JGE     STORE_BAR               ;If non-zero, OK.
  352.                XOR     AX,AX                   ;Else, use zero.
  353. STORE_BAR:     MOV     LAST_BAR,AX             ;Last bar location = count.
  354.                CALL    DISPLAY_DIRS            ;Update the directory file
  355.                                                ; count.
  356.                RET
  357.  
  358. ;----------------------------------------------;
  359. DO_ALL:        MOV     SI,AX                   ;Current counter.
  360.                MOV     DI,AX
  361.                JZ      ALL_MATCH               ;If name same, check date.
  362.                JB      ALL_LEFT2               ;Else, update the one
  363.                CALL    UPDATE_LIST2            ; earlier in the alphabet
  364.                JMP     SHORT ALL_END           ; with current display order.
  365.  
  366. ALL_MATCH:     CALL    DO_DATE
  367.                JB      ALL_LEFT1
  368.                JA      ALL_RIGHT1
  369.                OR      DI,8000H                ;Highlight flag.
  370. ALL_RIGHT1:    OR      SI,8000H
  371.                JMP     SHORT ALL_UPDATE
  372. ALL_LEFT1:     OR      DI,8000H
  373. ALL_UPDATE:    CALL    UPDATE_LIST2
  374.  
  375. ALL_LEFT2:     CALL    UPDATE_LIST1
  376. ALL_END:       INC     AX                      ;Increment counter.
  377.                RET
  378.  
  379. ;----------------------------------------------;
  380. DO_UNIQUE:     MOV     SI,AX
  381.                MOV     DI,AX
  382.                JZ      UNIQUE_MATCH            ;If match, check date.
  383.                JA      UNIQUE_RIGHT            ;Else, update the one
  384.                INC     AX                      ; earlier in the alphabetic
  385.                JMP     SHORT UNIQUE_LEFT       ; with current display order.
  386. UNIQUE_RIGHT:  INC     AX
  387.                CALL    UPDATE_LIST2
  388.                JMP     SHORT UNIQUE_END
  389.  
  390. UNIQUE_MATCH:  CALL    DO_DATE
  391.                JB      UNIQUE_LEFT1
  392.                JA      UNIQUE_RIGHT1
  393.                MOV     SI,-1                   ;Non-display flag.
  394.                MOV     DI,-1
  395.                JMP     SHORT UNIQUE_UPDATE
  396. UNIQUE_RIGHT1: OR      SI,8000H                ;Highlight flag.
  397.                JMP     SHORT UNIQUE_DATE
  398. UNIQUE_LEFT1:  OR      DI,8000H
  399. UNIQUE_DATE:   INC     AX
  400.  
  401. UNIQUE_UPDATE: CALL    UPDATE_LIST2
  402. UNIQUE_LEFT:   CALL    UPDATE_LIST1
  403. UNIQUE_END:    RET
  404.  
  405. ;----------------------------------------------;
  406. DO_ALIKE:      MOV     SI,AX
  407.                MOV     DI,AX
  408.                JZ      ALIKE_MATCH             ;If match, then check date.
  409.                MOV     SI,-1
  410.                JB      ALIKE_LEFT
  411.                MOV     DI,-1                   ;Else, update the one earlier
  412.                CALL    UPDATE_LIST2            ; in the alphabet with a -1
  413.                JMP     SHORT ALIKE_END         ; non-display flag.
  414.  
  415. ALIKE_MATCH:   INC     AX
  416.                CALL    DO_DATE
  417.                JB      ALIKE_LEFT1
  418.                JA      ALIKE_RIGHT1
  419.                OR      DI,8000H
  420. ALIKE_RIGHT1:  OR      SI,8000H
  421.                JMP     SHORT ALIKE_UPDATE
  422. ALIKE_LEFT1:   OR      DI,8000H
  423.  
  424. ALIKE_UPDATE:  CALL    UPDATE_LIST2
  425. ALIKE_LEFT:    CALL    UPDATE_LIST1
  426. ALIKE_END:     RET
  427.  
  428. ;-----------------------------------------------------------------------------;
  429. ; INPUT: BX -> Source name; BP -> target name; OUTPUT: ZF = 1 if date matched. ;
  430. ;-----------------------------------------------------------------------------;
  431. DO_DATE:       PUSH    SI
  432.                PUSH    DI
  433.                MOV     SI,BX                   ;Get filename pointers again.
  434.                MOV     DI,BP
  435.                ADD     SI,DOS_DATE             ;Point to date/time in DOS
  436.                ADD     DI,DOS_DATE             ; format and compare.
  437.                MOV     CX,(SIZE DOS_DATE + SIZE DOS_TIME) / 2
  438.                REP     CMPSW
  439.                POP     DI
  440.                POP     SI
  441.                RET
  442.  
  443. ;----------------------------------------------;
  444. UPDATE_LIST1:  MOV     DISP_ORDER[BX],SI       ;Store the display order value.
  445.                ADD     BX,SIZE FILE_RECORD     ;Point to next filename.
  446.                INC     SI                      ;Is it -1, non-display marker?
  447.                JZ      LIST1_END               ;If yes, done here.
  448.                INC     CS:SOURCE_COUNT         ;Else, increment file count.
  449. LIST1_END:     RET
  450.  
  451. UPDATE_LIST2:  MOV     ES:DISP_ORDER[BP],DI    ;Same for the second batch of
  452.                ADD     BP,SIZE FILE_RECORD     ; of filenames.
  453.                INC     DI                      ;Is it -1, non-display marker?
  454.                JZ      LIST2_END               ;If yes, done here.
  455.                INC     CS:TARGET_COUNT         ;Else, increment file count.
  456. LIST2_END:     RET
  457.  
  458. ;----------------------------------------------;
  459. DISP_LISTINGS: PUSH    DS                      ;Preserve data segment.
  460.                PUSH    SI
  461.                MOV     BP,LISTING_LINE         ;1st line of listing to
  462.                                                ; display.
  463.                MOV     CX,PAGE_LENGTH          ;No. of lines to display.
  464.                XOR     SI,SI                   ;SI -> start of source.
  465.                XOR     DX,DX                   ;DX -> start of target.
  466.                MOV     DI,(3 * 160)            ;Start display row 2; column 1.
  467. NEXT_LIST:     PUSH    CX                      ;Preserve lines to display.
  468.                MOV     DS,CS:SOURCE_SEG        ;1st in left half of screen.
  469.                MOV     CX,40                   ;39 chars in filename plus
  470.                                                ; mark.
  471.                PUSH    DX                      ;Preserve DX.
  472.                CALL    DO_LIST                 ;Display the left half of line.
  473.                POP     DX                      ;Restore DX.
  474.                XCHG    SI,DX                   ;Now point to target filename.
  475.                MOV     DS,CS:TARGET_SEG        ;Also need the segment.
  476.                INC     DI                      ;Bump pointer to next line.
  477.                INC     DI
  478.                MOV     CX,39                   ;It is 39 chars too.
  479.                PUSH    DX                      ;Preserve DX.
  480.                CALL    DO_LIST                 ;Display the right half of
  481.                                                ; line.
  482.                POP     DX                      ;Restore DX.
  483.                XCHG    SI,DX                   ;Restore pointers.
  484.                INC     BP                      ;Next order counter.
  485.                POP     CX                      ;Retrieve line counter.
  486.                LOOP    NEXT_LIST               ;Do all lines.
  487.                POP     SI
  488.                POP     DS                      ;Restore data segment.
  489.                RET                             ;Done here.
  490.  
  491. ;---------------------------------------------------------------;
  492. ; INPUT: DS:SI -> filename to display; Entry point at DO_LIST.  ;
  493. ;---------------------------------------------------------------;
  494. NEXT_REC1:     ADD     SI,SIZE FILE_RECORD     ;Next filename.
  495. DO_LIST:       MOV     BH,CS:BODY_ATTR         ;Assume body attribute.
  496.                CMP     LIST_NAME[SI],-1        ;Is this end of listing?
  497.                JZ      PAD_LINE                ;If yes, pad line with spaces.
  498.                MOV     AX,DISP_ORDER[SI]       ;Retrieve display order.
  499.                CMP     AX,-1                   ;Should it be displayed?
  500.                JZ      NEXT_REC1               ;If no, next record.
  501.                TEST    AX,8000H                ;Highlight bit?
  502.                JZ      COMPARE_ORDER           ;If no, use body attribute.
  503.                MOV     BH,CS:HIGHLIGHT_ATTR    ;Else, highlight.
  504.                AND     AX,NOT 8000H            ;Strip highlight bit.
  505. COMPARE_ORDER: CMP     AX,BP                   ;Else, entry less than order?
  506.                JB      NEXT_REC1               ;If yes, next record.
  507.                JA      PAD_LINE                ;If above, pad with spaces.
  508.  
  509.                CMP     CX,40                   ;Is this the source directory?
  510.                JNZ     DO_CHAR2                ;If no, skip mark field.
  511.                MOV     AL,MARK[SI]             ;Else, retrieve mark.
  512.                CALL    WRITE_SCREEN            ;Write it to display.
  513.                DEC     CX                      ;Adjust count acting as flag.
  514.                CMP     CS:BAR_LINE,BP          ;Is this the bar line?
  515.                JNZ     DO_CHAR2                ;If no, write the line.
  516.                PUSH    BX                      ;Else, preserve attribute.
  517.                MOV     BH,CS:BAR_ATTR          ;Retrieve bar attribute.
  518.                MOV     CX,SIZE LIST_NAME       ;Write name with bar attribute.
  519. DO_CHAR1:      LODSB
  520.                CALL    WRITE_SCREEN
  521.                LOOP    DO_CHAR1
  522.                POP     BX                      ;Retrieve display attribute.
  523.                MOV     CX,39 - SIZE LIST_NAME  ;Rest of name.
  524. DO_CHAR2:      LODSB                           ;Display the filename.
  525.                CALL    WRITE_SCREEN
  526.                LOOP    DO_CHAR2
  527.                ADD     SI,7                    ;Past date/time/order/mark
  528.                JMP     SHORT DO_LIST_END       ; fields.
  529.  
  530. PAD_LINE:      CMP     CX,40                   ;Is this source directory?
  531.                JNZ     DO_PAD2                 ;If no, just write spaces.
  532.                MOV     AL,SPACE                ;Else, write one space as mark.
  533.                CALL    WRITE_SCREEN
  534.                DEC     CX                      ;Adjust counter flag.
  535.                CMP     CS:BAR_LINE,BP          ;Is this the bar line?
  536.                JNZ     DO_PAD2                 ;If no, write line.
  537.                PUSH    BX                      ;Else, display bar and
  538.                MOV     BH,CS:BAR_ATTR          ; then rest of blank line.
  539.                MOV     CX,SIZE LIST_NAME
  540. DO_PAD1:       MOV     AL,SPACE
  541.                CALL    WRITE_SCREEN
  542.                LOOP    DO_PAD1
  543.                POP     BX
  544.                MOV     CX,39 - SIZE LIST_NAME
  545. DO_PAD2:       MOV     AL,SPACE
  546.                CALL    WRITE_SCREEN
  547.                LOOP    DO_PAD2
  548. DO_LIST_END:   RET
  549.  
  550. ;-------------------------------------------------------------------------;
  551. ; INPUT:  SI -> string to parse.                                          ;
  552. ; OUTPUT: BP -> filespec start; SI -> filespec end; BX -> filename start. ;
  553. ;         ZF = 1 if null string.                                          ;
  554. ;-------------------------------------------------------------------------;
  555. PARSE_SPEC:    LODSB                           ;Get a byte.
  556.                CMP     AL,SPACE                ;Is it a space char or below?
  557.                JA      LEADING_END             ;If no, found start.
  558.                CMP     AL,CR                   ;Is it carriage return?
  559.                JNZ     PARSE_SPEC              ;If no, get next byte.
  560. LEADING_END:   DEC     SI                      ;Adjust pointer to string
  561.                                                ; start.
  562.                MOV     BP,SI                   ;Save start of filespec.
  563.                MOV     BX,SI                   ;Use BX as filename start
  564.                                                ; pointer
  565.  
  566. FIND_END:      LODSB                           ;Get a byte.
  567.                CMP     AL,":"                  ;Is it a drive delimiter?
  568.                JNZ     CK_SLASH                ;If no, check path delimiter.
  569.                MOV     DL,[SI-2]               ;Else, retrieve drive
  570.                                                ; specifier.
  571.                AND     DL,5FH                  ;Capitalize.
  572.                SUB     DL,"A"                  ;Convert to DOS format.
  573.                MOV     AH,0EH                  ;Change drive.
  574.                INT     21H
  575.                MOV     BX,SI                   ;Save as filename start.
  576.                MOV     AH,19H                  ;Get current disk.
  577.                INT     21H
  578.                CMP     AL,DL                   ;Was it a valid disk request?
  579.                JZ      FIND_END                ;If yes, continue parsing.
  580. FIND_DELIMIT:  LODSB                           ;Else, find delimiter
  581.                CMP     AL,SPACE
  582.                JA      FIND_DELIMIT
  583.                DEC     SI
  584.                MOV     BP,SI                   ; and emulate null string.
  585.                JMP     SHORT PARSE_END
  586.  
  587. CK_SLASH:      CMP     AL,"\"                  ;Is it a path delimiter?
  588.                JNZ     CK_DELIMITER            ;If no, check switch character.
  589.                MOV     BX,SI                   ;Else, save as filename start.
  590. CK_DELIMITER:  CMP     AL,"/"                  ;Is it a switch delimiter?
  591.                JZ      FOUND_END               ;If yes, end of filespec.
  592.                CMP     AL,SPACE                ;Is it above space character?
  593.                JA      FIND_END                ;If yes, continue until find
  594.                                                ; end.
  595.  
  596. FOUND_END:     DEC     SI                      ;Adjust.
  597.                PUSH    SI
  598.                MOV     SI,OFFSET CURRENT_DIR   ;Get default directory.
  599.                CALL    GET_DIR
  600.                POP     SI
  601. PARSE_END:     CMP     BP,SI                   ;Any filespec?
  602.                RET                             ;Return result to caller.
  603.  
  604. ;-----------------------------------------------------------;
  605. ; INPUT:  DI = 0 for first prompt, DI = 1 for second prompt ;
  606. ; OUTPUT: SI -> string start.                               ;
  607. ;-----------------------------------------------------------;
  608. PROMPT_USER:   CMP     SYNTAX_FLAG,1           ;If first time through, display
  609.                JZ      PROMPT                  ; syntax message.
  610.                MOV     SYNTAX_FLAG,1
  611.                CALL    CLS
  612.                XOR     DX,DX
  613.                CALL    SET_CURSOR
  614.                MOV     DX,OFFSET SIGNATURE
  615.                CALL    PRINT_STRING
  616.  
  617. PROMPT:        MOV     DX,OFFSET SOURCE_PROMPT ;Point to appropriate prompt
  618.                OR      DI,DI
  619.                JZ      DISP_PROMPT
  620.                MOV     DX,OFFSET TARGET_PROMPT
  621. DISP_PROMPT:   CALL    PRINT_STRING            ; and display it.
  622.                MOV     DX,OFFSET NOT_FOUND
  623.                CALL    PRINT_STRING
  624.                MOV     SI,OFFSET USER_INPUT    ;User input storage.
  625.                MOV     BYTE PTR [SI],65        ;Maximum of 65 characters.
  626.                MOV     DX,SI
  627.                MOV     AH,0AH
  628.                INT     21H                     ;Buffered Keyboard Input.
  629.                INC     SI
  630.                MOV     BYTE PTR [SI],SPACE     ;Emulate command line entry.
  631.                INC     SI                      ;SI -> string.
  632.                RET
  633.  
  634. ;-------------------------------------------------------------------------;
  635. ; INPUT:  BP -> filespec start; SI -> filespec end; BX -> filename start. ;
  636. ;         DI -> filespec storage;                                         ;
  637. ; OUTPUT: SI -> path end; CY = 0 if filespec exist; CY = 1 if not exist.  ;
  638. ;-------------------------------------------------------------------------;
  639. FIND_PATH:     MOV     BYTE PTR [SI],0         ;ASCIIZ the string.
  640.                CMP     BYTE PTR [SI - 1],":"   ;Drive-only?
  641.                JZ      DO_GLOBAL               ;If yes, use global.
  642. CK_ROOT:       MOV     CX,1                    ;CX=1:"\"not=root
  643.                                                ;CX=0:"\"=root.
  644.                CMP     BYTE PTR [BX - 1],"\"   ;Filespec start path delimiter?
  645.                JNZ     CK_PATH                 ;If no, not root.
  646.                CMP     BYTE PTR [BX - 2],":"   ;Else, prefaced with colon
  647.                JZ      ROOT                    ;If yes, then root.
  648.                CMP     BYTE PTR [BX - 2],SPACE ;Prefaced with white space?
  649.                JA      CK_TRAILING             ;If no, then trailing slash?
  650. ROOT:          DEC     CX                      ;Else, root; CX=0 for root
  651.                                                ; flag.
  652.                JMP     SHORT CK_PATH           ;Change default path.
  653.  
  654. CK_TRAILING:   CMP     BX,SI                   ;Filename start = filespec end?
  655.                JNZ     CK_PATH                 ;If no, not trailing slash.
  656.                MOV     BYTE PTR [BX - 1],0     ;Else, zero out trailing slash
  657.                MOV     BX,OFFSET STAR_DOT_STAR ; and use global filespec.
  658.  
  659. CK_PATH:       MOV     DX,BP                   ;See if filespec is a path
  660.                CALL    CHANGE_DIR              ; by changing directory.
  661.                JC      CK_FILESPEC             ;If failed, remove filename.
  662. DO_GLOBAL:     MOV     BX,OFFSET STAR_DOT_STAR ;Else, use global for filename.
  663.                JMP     SHORT GOT_FILESPEC      ;Done here.
  664.  
  665. CK_FILESPEC:   JCXZ    SAVE_DELIMIT            ;Is path root?
  666.                                                ; If yes leave "\".
  667.                DEC     BX                      ;Else, point to slash.
  668. SAVE_DELIMIT:  PUSH    [BX]                    ;Preserve filename start.
  669.                MOV     BYTE PTR [BX],0         ;Temp ASCIIZ twixt path and
  670.                                                ; name.
  671.                CALL    CHANGE_DIR              ;Change directory.
  672.                POP     [BX]                    ;Restore first byte of
  673.                                                ; filename.
  674.                PUSHF                           ;Save CHDIR status.
  675.                JCXZ    CK_FILENAME             ;If root, done here.
  676.                INC     BX                      ;Else, re-adjust filename
  677.                                                ; pointer.
  678. CK_FILENAME:   POPF                            ;Retrieve CHDIR status.
  679.                JNC     GOT_FILESPEC            ;If successful, got filespec.
  680.                CALL    FIND_FIRST              ;Else, check if filename.
  681.                JC      RESTORE_DRIVE           ;If not, invalid filespec.
  682.  
  683. GOT_FILESPEC:  MOV     AH,19H                  ;Get current drive.
  684.                INT     21H
  685.                ADD     AL,"A"                  ;Convert to ASCII.
  686.                MOV     [DI + SPEC_LENGTH],AL   ;Make a copy.
  687.                STOSB                           ;Store it.
  688.                MOV     AL,":"                  ;Add colon delimiter.
  689.                MOV     [DI + SPEC_LENGTH],AL   ;Make a copy.
  690.                STOSB
  691.                MOV     SI,DI
  692.                ADD     DI,SPEC_LENGTH
  693.                CALL    GET_DIR                 ;Add complete path via DOS.
  694.                DEC     SI                      ;Point to "\".
  695. PATH_END:      LODSB                           ;Make a copy and at the same
  696.                STOSB                           ; time find end of path.
  697.                OR      AL,AL
  698.                JNZ     PATH_END
  699.                DEC     DI                      ;Point to end of path.
  700.                PUSH    DI                      ;Add save it.
  701.                DEC     SI                      ;Adjust spec path pointer also.
  702.                MOV     DI,SI
  703.                MOV     SI,BX
  704.                CALL    ADD_NAME                ;Add spec to end of path.
  705.  
  706.                MOV     DX,OFFSET CURRENT_DIR   ;Restore default directory.
  707.                CALL    CHANGE_DIR
  708.                POP     SI                      ;Return path end pointer.
  709.                CLC                             ;Successful.
  710.  
  711. RESTORE_DRIVE: PUSHF
  712.                MOV     DL,DEFAULT_DRIVE        ;Restore default drive.
  713.                MOV     AH,0EH
  714.                INT     21H
  715.                POPF
  716.                RET
  717.  
  718. ;-----------------------------------------------------------------------------;
  719. ; INPUT:  DX -> Complete filespec;  BP -> Seg name storage.                    ;
  720. ; OUTPUT: BP:DI -> Storage end;  CY = 0 if successful                          ;
  721. ;         CY = 1 if segment full or ran out of memory and DX -> Error message. ;
  722. ;-----------------------------------------------------------------------------;
  723. FIND_FILES:    PUSH    ES                      ;Preserve extra segment.
  724.                MOV     ES,BP                   ;ES:DI -> filename storage.
  725.                XOR     DI,DI
  726.                MOV     WORD PTR ES:[DI],-1     ;Assume empty directory.
  727.                CALL    FIND_FIRST              ;Any files?
  728.                JC      FILES_DONE              ;If no, assumed right.
  729.  
  730. FIND_NEXT:     CALL    STORE_NAME              ;Store a filename.
  731.                CALL    CK_AVAIL                ;Make sure we not out of
  732.                                                ; memory.
  733.                JC      FILES_END               ;If not enough, exit.
  734.                MOV     AH,4FH                  ;Find Next Matching.
  735.                INT     21H
  736.                JNC     FIND_NEXT               ;If successful store filename.
  737.                MOV     AX,-1                   ;Else, mark the end with -1.
  738.                STOSW
  739.                CALL    SORT                    ;Sort 'em.
  740. FILES_DONE:    CLC                             ;No error so CY = 0.
  741. FILES_END:     POP     ES                      ;Restore extra segment.
  742.                RET
  743.  
  744. ;---------------------------------------------------------------------;
  745. ; INPUT: ES segment of filenames to sort;  Selection sort algorithm.  ;
  746. ;---------------------------------------------------------------------;
  747. SORT:          PUSH    DS                      ;Preserve couple registers.
  748.                PUSH    DI
  749.                PUSH    ES
  750.                POP     DS                      ;DS = ES.
  751.                XOR     SI,SI                   ;SI = first record.
  752.  
  753. NEXT_SORT:     MOV     AX,SI                   ;Carry source pointer in AX.
  754.                MOV     BX,SI                   ;Carry destination pointer in DX.
  755.                ADD     BX,SIZE FILE_RECORD
  756.                CMP     WORD PTR [BX],-1        ;Sort is done when last record.
  757.                JZ      SORT_END
  758.  
  759.                PUSH    SI                      ;Save record pointer.
  760. NEXT_RECORD:   MOV     SI,AX                   ;Restore inside loop pointers.
  761.                MOV     DI,BX
  762.                MOV     CX,SIZE LIST_NAME       ;Filename length.
  763.                REPZ    CMPSB                   ;Compare the name fields.
  764.                JB      NO_SWITCH               ;If below, no switch.
  765. SWAP:          MOV     AX,BX                   ;Else, AX = selected record.
  766.  
  767. NO_SWITCH:     ADD     BX,SIZE FILE_RECORD     ;Move to next record in list.
  768.                CMP     WORD PTR [BX],-1        ;End of list?
  769.                JNZ     NEXT_RECORD             ;If no, continue.
  770.  
  771.                POP     SI                      ;Else, restore outside loop
  772.                                                ; ptr.
  773.                CMP     SI,BX                   ;Did we make a selection?
  774.                JZ      SELECT_LOOP             ;If no, go to next list.
  775.  
  776.                PUSH    SI                      ;Else, save pointer.
  777.                MOV     CX,(SIZE FILE_RECORD - 2) / 2
  778.                MOV     DI,AX
  779. NEXT_SWAP:     MOV     AX,[DI]                 ;Swap the selection into place.
  780.                MOVSW
  781.                MOV     [SI - 2],AX
  782.                LOOP    NEXT_SWAP
  783.                POP     SI
  784.  
  785. SELECT_LOOP:   ADD     SI,SIZE FILE_RECORD     ;Next record.
  786.                JMP     NEXT_SORT
  787.  
  788. SORT_END:      POP     DI                      ;Restore registers.
  789.                POP     DS
  790.                RET
  791.  
  792. ;----------------------------------------------------------------------------;
  793. ; INPUT: ES:DI pointer; OUTPUT: CY = 1 if segment full or ran out of memory  ;
  794. ;----------------------------------------------------------------------------;
  795. CK_AVAIL:      CMP     DI,65535 - (2 * SIZE FILE_RECORD)   ;End of segment?
  796.                MOV     DX,OFFSET TOO_MANY
  797.                JA      AVAIL_END               ;If yes, too many files.
  798.                MOV     AX,DI                   ;Else, calculate the pointer
  799.                ADD     AX,16 + 15              ; in paragraphs.
  800.                MOV     CL,4
  801.                SHR     AX,CL
  802.                MOV     BX,ES
  803.                ADD     AX,BX
  804.                CMP     AX,TOP_MEMORY           ;Top of memory?
  805.                MOV     DX,OFFSET OUT_OF_MEMORY ;If yes, not enough memory.
  806.                JA      AVAIL_END
  807.                STC
  808. AVAIL_END:     CMC                             ;Complement the carry status.
  809.                RET
  810.  
  811. ;----------------------------------------------------------------------;
  812. ; INPUT: BP:DI = current seg:off;  OUTPUT: BP = start of new segment.  ;
  813. ;----------------------------------------------------------------------;
  814. CALC_SEG:      ADD     DI,SIZE FILE_RECORD + 15
  815.                MOV     CL,4
  816.                SHR     DI,CL
  817.                ADD     BP,DI
  818.                RET
  819.  
  820. ;--------------------------------------------------------------------------;
  821. ; Keyboard subroutines.                                                    ;
  822. ; INPUT: BP = BAR_LINE; BX = LISTING_LINE; CX = LAST_BAR; DX = PAGE_LENGTH ;
  823. ;--------------------------------------------------------------------------;
  824. PLUS:          MOV     AL,LITTLE_ARROW         ;Use little right arrow for
  825.                                                ; mark.
  826.                JMP     SHORT PLUSMINUS
  827.  
  828. MINUS:         MOV     AL,SPACE                ;Remove mark with space char.
  829.  
  830. PLUSMINUS:     PUSH    DS                      ;Preserve some registers.
  831.                PUSH    BX
  832.                CALL    FIND_BAR                ;Find bar record.
  833.                JC      PLUSMINUS_END           ;If on blank line, skip.
  834.                MOV     MARK[SI],AL             ;Else, store the mark.
  835. PLUSMINUS_END: POP     BX                      ;Restore registers.
  836.                POP     DS
  837.                MOV     AH,2
  838.                INT     16H                     ;Shift key pressed?
  839.                TEST    AL,SHIFT_KEYS           ;If no, move down line.
  840.                JZ      DOWN                    ;Else, move up a line.
  841.  
  842. UP:            DEC     BP                      ;Move bar up a line.
  843.                JL      PAGEKEY_END             ;If < 0, ignore.
  844.                CMP     BP,BX                   ;If bar below top, OK.
  845.                JAE     PAGE_UPDATE
  846.                DEC     BX                      ;Else, move listing up a line.
  847.                JMP     SHORT PAGE_UPDATE
  848.  
  849. DOWN:          INC     BP                      ;Move bar down a line.
  850.                CMP     BP,CX                   ;If > last line, then ignore.
  851.                JA      PAGEKEY_END
  852.                ADD     DX,BX                   ;Listing top + page length =
  853.                CMP     BP,DX                   ; listing bottom; If bar below
  854.                JB      PAGE_UPDATE             ; listing bottom, OK.
  855.                INC     BX                      ;Else move listing down a line.
  856.                JMP     SHORT PAGE_UPDATE
  857.  
  858. PGUP:          SUB     BP,DX                   ;Move bar up a page.
  859.                SUB     BX,DX                   ;Move listing up a page.
  860.                JC      HOME                    ;If listing < top, then home.
  861.                JMP     SHORT PAGE_UPDATE       ;Else, OK.
  862.  
  863. PGDN:          ADD     BX,DX                   ;Move listing down a page.
  864.                CMP     BX,CX                   ;If <= last line, do bar.
  865.                JBE     DO_BAR
  866.                SUB     BX,DX                   ;Else, back to where we were
  867.                MOV     BP,CX                   ; and move bar to last line
  868.                JMP     SHORT PAGE_UPDATE       ; and update.
  869. DO_BAR:        ADD     BP,DX                   ;Move bar down a page.
  870.                CMP     BP,CX                   ;If bar <= last line, OK.
  871.                JBE     PAGE_UPDATE
  872.                MOV     BP,CX                   ;Else, move bar to last line.
  873.                JMP     SHORT PAGE_UPDATE
  874.  
  875. HOME:          XOR     BP,BP                   ;Move bar to top.
  876.                XOR     BX,BX                   ;Move listing to top.
  877.                JMP     SHORT PAGE_UPDATE
  878.  
  879. END_KEY:       MOV     BP,CX                   ;Move bar to last line.
  880.                INC     CX                      ;Last line + 1 - page length =
  881.                SUB     CX,DX                   ; top of last page.
  882.                CMP     BX,CX                   ;If less than a full page,
  883.                JG      PAGE_UPDATE             ; then already at last page.
  884.                MOV     BX,CX                   ;Else, move listing to last
  885.                                                ; page.
  886.                JMP     SHORT PAGE_UPDATE
  887.  
  888. PAGE_UPDATE:   MOV     BAR_LINE,BP             ;Store the new bar
  889.                MOV     LISTING_LINE,BX         ; and listing line start.
  890. PAGEKEY_END:   RET
  891.  
  892. ;----------------------------------------------;
  893. F1:            MOV     AH,FILES_MODE           ;Retrieve current file mode.
  894.                INC     AH                      ;Go to next mode.
  895.                INC     AH
  896.                CMP     AH,ALIKE                ;Is it above last mode, Alike?
  897.                JBE     F1_STORE                ;If no, OK.
  898.                XOR     AH,AH                   ;Else, wrap to All file mode.
  899.                JMP     SHORT F1_STORE          ;Store and update.
  900.  
  901. S_F1:          MOV     AH,FILES_MODE           ;Retrieve current file mode.
  902.                DEC     AH                      ;Reverse direction.
  903.                DEC     AH
  904.                CMP     AH,ALL                  ;Is it below All file mode?
  905.                JGE     F1_STORE                ;If no, OK.
  906.                MOV     AH,ALIKE                ;Else, wrap to last mode,
  907.                                                ; Alike?
  908.  
  909. F1_STORE:      MOV     FILES_MODE,AH           ;Store new mode.
  910.                CALL    DISPLAY_MENU            ;Update the menu.
  911.                CALL    MATCH                   ;Update the matches.
  912.                RET
  913.  
  914. ;----------------------------------------------;
  915. F2:            MOV     AL,LITTLE_ARROW         ;Mark all records with little
  916.                JMP     SHORT DO_MARKS          ; right arrow.
  917.  
  918. ;----------------------------------------------;
  919. F3:            MOV     AL,SPACE                ;Mark all records with space
  920.                                                ; char
  921. DO_MARKS:      PUSH    DS
  922.                MOV     DS,SOURCE_SEG
  923.                XOR     SI,SI                   ;DS:SI -> source records.
  924.                JMP     SHORT DO_MARK
  925. NEXT_ALL:      ADD     SI,SIZE FILE_RECORD     ;Next record.
  926. DO_MARK:       CMP     LIST_NAME[SI],-1        ;Is this last record?
  927.                JZ      MARKS_END               ;If yes, done.
  928.                MOV     MARK[SI],AL             ;Else, store mark.
  929.                JMP     SHORT NEXT_ALL
  930. MARKS_END:     POP     DS
  931.                RET
  932.  
  933. ;----------------------------------------------;
  934. F4:            MOV     RESPONSE,OFFSET COPY_MSG
  935.                JMP     SHORT CK_COPY
  936.  
  937. F5:            MOV     RESPONSE,OFFSET MOVE_MSG
  938.                CMP     FILES_MODE,ALIKE        ;Can't move files in alike
  939.                                                ; mode.
  940.                JNZ     CK_COPY
  941.                CALL    BEEP
  942.                RET
  943.  
  944. CK_COPY:       PUSH    DS                      ;Preserve data segment.
  945.                MOV     DS,SOURCE_SEG           ;DS:SI -> source records.
  946.                XOR     SI,SI
  947.                XOR     CX,CX                   ;Initialize counter to zero.
  948.                JMP     SHORT COUNT_MARKS       ;Count the marks.
  949. FOUND_MARK:    INC     CX                      ;Increment count.
  950. NEXT_COUNT:    ADD     SI,SIZE FILE_RECORD     ;Next record.
  951. COUNT_MARKS:   CMP     LIST_NAME[SI],-1        ;Last record?
  952.                JZ      GOT_COUNT               ;If yes, got count of marks.
  953.                CMP     DISP_ORDER[SI],-1       ;Else, is record displayed?
  954.                JZ      NEXT_COUNT              ;If no, skip.
  955.                CMP     MARK[SI],LITTLE_ARROW   ;Else, is it marked?
  956.                JNZ     NEXT_COUNT              ;If no, skip.
  957.                JMP     FOUND_MARK              ;Else, count it.
  958. GOT_COUNT:     POP     DS                      ;Restore data segment.
  959.  
  960.                MOV     MARKED_COUNT,CX         ;Save count of marks.
  961.                JCXZ    COPY_BAR                ;If none marked, copy bar.
  962.                CALL    GET_COUNT               ;Else, convert count to ASCII.
  963.                MOV     BX,OFFSET MARKED_MSG    ;Will display marked message.
  964.                CALL    GET_RESPONSE            ;Ask user if should continue.
  965.                JNZ     COPY_MARKED             ;If confirmed, continue.
  966.                JMP     F4_END                  ;Else, exit.
  967.  
  968. COPY_MARKED:   PUSH    LISTING_LINE            ;Preserve current page
  969.                PUSH    BAR_LINE                ; and bar line.
  970.                CALL    HOME                    ;Start searching for marked
  971.                XOR     SI,SI                   ; files from home position.
  972.                JMP     SHORT CK_ABORT          ;Go check keypress for abort.
  973.  
  974. NEXT_REC3:     ADD     SI,SIZE FILE_RECORD     ;Next record.
  975. NEXT_MARKED:   MOV     BP,BAR_LINE             ;Paging commands need line
  976.                MOV     BX,LISTING_LINE         ; page data.
  977.                MOV     CX,LAST_BAR
  978.                MOV     DX,PAGE_LENGTH
  979.                CALL    DOWN                    ;Move bar down a line.
  980.  
  981. CK_ABORT:      CALL    CK_KEY                  ;Any keypress?
  982.                JNZ     MARKED_END              ;If yes, quite copying.
  983.                CALL    DISP_LISTINGS           ;Else, display current bar.
  984.                PUSH    DS
  985.                MOV     DS,SOURCE_SEG
  986.                MOV     AX,DISP_ORDER[SI]       ;Retrieve display order and
  987.                MOV     BL,MARK[SI]             ; mark of current record.
  988.                POP     DS
  989.                CMP     AX,-1                   ;Is it displayed?
  990.                JNZ     CK_BAR                  ;If yes, see if bar record.
  991.                ADD     SI,SIZE FILE_RECORD     ;Else, next record.
  992.                JMP     CK_ABORT
  993.  
  994. CK_BAR:        AND     AX,NOT 8000H            ;Else, strip highlight bit.
  995.                CMP     AX,BAR_LINE             ;Is it current line?
  996.                JA      NEXT_MARKED             ;If above, skip for now.
  997.                CMP     BL,LITTLE_ARROW         ;Is it marked?
  998.                JNZ     NEXT_REC3               ;If no, next record.
  999.  
  1000.                MOV     BP,SI                   ;Else, copy; First convert name
  1001.                CALL    GET_SOURCE              ; back to dot delimited ASCIIZ.
  1002.                CALL    COPY                    ;Copy the file.
  1003.                JC      MARKED_END              ;If failed, exit.
  1004.                MOV     SI,BP                   ;Else, retrieve record pointer.
  1005.                DEC     MARKED_COUNT            ;Decrement marked count.
  1006.                JNZ     NEXT_REC3               ;Continue until zero.
  1007.                CALL    DISP_LISTINGS           ;Display last asterisk.
  1008.  
  1009. MARKED_END:    POP     BAR_LINE                ;Restore bar and page.
  1010.                POP     LISTING_LINE
  1011.                JMP     SHORT F4_REREAD         ;Done.
  1012.  
  1013. ;----------------------------------------------;
  1014. COPY_BAR:      PUSH    DS
  1015.                CALL    FIND_BAR                ;Find bar record.
  1016.                POP     DS
  1017.                JNC     VALID_BAR               ;Is bar on blank line?
  1018.                CALL    BEEP                    ;If yes, beep and exit.
  1019.                JMP     SHORT F4_END
  1020. VALID_BAR:     MOV     BP,SI                   ;Else, convert name to dot
  1021.                CALL    GET_SOURCE              ; delimited ASCIIZ.
  1022.                XOR     BX,BX                   ;No "marked files" message.
  1023.                CALL    GET_RESPONSE            ;Ask user for confirmation.
  1024.                JZ      F4_END                  ;If aborted, exit.
  1025.                CALL    COPY                    ;Else, copy the highlighted
  1026.                                                ; file.
  1027.  
  1028. F4_REREAD:     CMP     RESPONSE,OFFSET MOVE_MSG  ;Did we move files?
  1029.                JNZ     READ_TARGET             ;If no, just read target.
  1030.                CALL    SOURCE_DIR              ;Else, get new source dir also.
  1031. READ_TARGET:   CALL    TARGET_DIR
  1032.                JNC     F4_UPDATE
  1033.                CALL    MENU_OFFSET             ;Calculate menu offset.
  1034.                ADD     DI,80 * 2               ;Place error message on second
  1035.                MOV     BH,MENU_ATTR            ; menu line with menu
  1036.                                                ; attribute.
  1037.                MOV     SI,DX                   ;Error message.
  1038.                CALL    WRITE_STRING            ;Write the message.
  1039.                MOV     SI,OFFSET PRESS_MSG
  1040.                CALL    WRITE_STRING
  1041.                CALL    HIDE_CURSOR             ;Rehide the cursor.
  1042.                CALL    BEEP                    ;Draw attention with beep.
  1043.                CALL    GET_KEY                 ;Pause for keystroke.
  1044.                CALL    CLS
  1045.                XOR     DX,DX
  1046.                CALL    SET_CURSOR
  1047.                JMP     ERROR                   ;Abort to DOS.
  1048.  
  1049. F4_UPDATE:     CMP     RESPONSE,OFFSET MOVE_MSG  ;Did we do a move?
  1050.                JZ      KEEP_BAR                  ;If yes, preserve bar/page.
  1051.                CMP     FILES_MODE,UNIQUE         ;Are different files
  1052.                                                  ; displayed?
  1053.                JNZ     KEEP_BAR                  ;If no, then preserve
  1054.                                                  ; bar/page.
  1055.                CALL    MATCH                     ;Else, home bar and page.
  1056.                JMP     SHORT F4_END
  1057. KEEP_BAR:      CALL    DO_MATCH
  1058.  
  1059. F4_END:        CALL    HIDE_CURSOR             ;Rehide the cursor.
  1060.                CALL    DISPLAY_MENU            ;Redisplay the menu.
  1061.                CALL    CLEAR_KEY               ;Clear the keyboard.
  1062.                RET                             ;Done.
  1063.  
  1064. ;--------------------------------------------------;
  1065. ; OUTPUT:  CY = 1 if failed; CY = 0 if successful. ;
  1066. ;--------------------------------------------------;
  1067. COPY:          MOV     SI,OFFSET SOURCE_NAME   ;Add filename to both source
  1068.                MOV     DI,SOURCE_END           ; and target path spec.
  1069.                CALL    ADD_NAME
  1070.                MOV     SI,OFFSET SOURCE_NAME
  1071.                MOV     DI,TARGET_END
  1072.                CALL    ADD_NAME
  1073.  
  1074.                MOV     DX,OFFSET SOURCE_FILE   ;Get attribute, size and date
  1075.                CALL    FIND_FIRST              ; of source file via 
  1076.                                                ; Find First.
  1077.                MOV     SI,OFFSET DTA
  1078.                MOV     DI,OFFSET SOURCE_STATS  ;Store the info.
  1079.                MOV     CX,SIZE MATCHING
  1080.                REP     MOVSB
  1081.  
  1082.                MOV     AX,3D00H                ;Open source file for reading.
  1083.                INT     21H
  1084.                JNC     SAVE_HANDLE
  1085.                JMP     COPY_END                ;If failed, exit.
  1086. SAVE_HANDLE:   MOV     DI,AX                   ;Else, save source handle.
  1087.  
  1088.                MOV     DX,OFFSET TARGET_FILE   ;Point to target name.
  1089.                CALL    FIND_FIRST              ;Does it exist?
  1090.                JNC     CK_IF_MOVE              ;If yes, see if move request.
  1091.                CALL    DISK_FREE               ;Else, get disk free space.
  1092.                JMP     SHORT CK_FREE           ;Go see if enough room.
  1093.  
  1094. CK_IF_MOVE:    CMP     RESPONSE,OFFSET MOVE_MSG ;Is it a move request?
  1095.                JNZ     CK_IF_SAME               ;If no, see if same as source.
  1096.                STC
  1097.                JMP     CLOSE_READ              ;Else, exit with error flag.
  1098.  
  1099. CK_IF_SAME:    MOV     CL,DTA.ATTRIBUTE        ;Get attribute of target
  1100.                XOR     CH,CH
  1101.                MOV     SI,CX                   ; and save.
  1102.                XOR     CX,1                    ;Flip read-only attribute.
  1103.                MOV     AX,4301H                ;Change file mode.
  1104.                INT     21H
  1105.                MOV     DX,OFFSET SOURCE_FILE   ;Now get source attribute.
  1106.                MOV     AX,4300H
  1107.                INT     21H
  1108.                JNC     CK_CHANGED
  1109.                JMP     COPY_END                   ;Exit if error.
  1110. CK_CHANGED:    CMP     CL,SOURCE_STATS.ATTRIBUTE  ;Else, see if it has
  1111.                                                   ; changed.
  1112.                PUSHF                              ;Save compare results.
  1113.                MOV     DX,OFFSET TARGET_FILE      ;Restore target attribute.
  1114.                MOV     CX,SI
  1115.                MOV     AX,4301H                 ;Change file mode.
  1116.                INT     21H
  1117.                POPF                             ;Retrieve compare results.
  1118.                STC                              ;Assume files are the same.
  1119.                JNZ     CLOSE_READ               ;If attr changed, they are
  1120.                                                 ; so exit
  1121.                CALL    DISK_FREE                ;Else, get disk free space.
  1122.                ADD     AX,DTA.SIZE_LOW
  1123.                ADC     DX,DTA.SIZE_HIGH           ;Target size + disk free.
  1124. CK_FREE:       SUB     AX,SOURCE_STATS.SIZE_LOW   ;Total - source size.
  1125.                SBB     DX,SOURCE_STATS.SIZE_HIGH
  1126.                JB      CLOSE_READ                 ;If negative, not enough
  1127.                                                   ; room.
  1128.  
  1129. CREATE:        MOV     DX,OFFSET TARGET_FILE   ;Create and truncate target
  1130.                XOR     CX,CX                   ; file to zero
  1131.                MOV     AH,3CH
  1132.                INT     21H
  1133.                JC      CLOSE_READ
  1134.                MOV     SI,AX                   ;Save handle.
  1135.                MOV     DS,BUFFER_SEG           ;Read/write buffer.
  1136.                XOR     DX,DX                   ;Offset zero.
  1137.  
  1138. COPY_READ:     MOV     BX,DI                   ;Retrieve read handle.
  1139.                MOV     CX,CS:BUFFER_SIZE       ;Buffer size.
  1140.                MOV     AH,3FH
  1141.                INT     21H                     ;Read source file.
  1142.                JC      COPY_DONE               ;If carry, failed; exit.
  1143.                OR      AX,AX                   ;If zero bytes read, done.
  1144.                JZ      CHANGE_DATE             ;Change target date to source.
  1145.  
  1146.                MOV     CX,AX                   ;Else, bytes read into counter.
  1147.                MOV     BX,SI                   ;Retrieve write handle.
  1148.                MOV     AH,40H
  1149.                INT     21H                     ;Write the buffer to disk.
  1150.                JC      COPY_DONE               ;If failed, exit.
  1151.                CMP     CX,AX                   ;Write same number as read?
  1152.                STC                             ;Assume no.
  1153.                JNZ     COPY_DONE               ;If no, failed; exit.
  1154.                CMP     CX,CS:BUFFER_SIZE       ;Was it a full read?
  1155.                JZ      COPY_READ               ;If yes, there must be more.
  1156.  
  1157. CHANGE_DATE:   MOV     BX,SI                         ;Write handle.
  1158.                MOV     CX,CS:SOURCE_STATS.FILE_TIME  ;Else, make time/date
  1159.                MOV     DX,CS:SOURCE_STATS.FILE_DATE  ; same as source.
  1160.                MOV     AX,5701H
  1161.                INT     21H
  1162.                MOV     DS,CS:SOURCE_SEG        ;Mark success with asterisk.
  1163.                MOV     DS:MARK[BP],"*"
  1164.  
  1165. COPY_DONE:     PUSH    CS                      ;Restore data segment.
  1166.                POP     DS
  1167.  
  1168. CLOSE_WRITE:   PUSHF                           ;Save error if any.
  1169.                MOV     BX,SI                   ;Close write file.
  1170.                MOV     AH,3EH
  1171.                INT     21H
  1172.                POP     AX                      ;Retrieve flags.
  1173.                JC      CLOSE_READ              ;Close successful?
  1174.                XCHG    AH,AL                   ;If no, exit with error, else
  1175.                SAHF                            ; retrieve write state.
  1176.  
  1177. CLOSE_READ:    PUSHF                           ;Save flags.
  1178.                MOV     BX,DI                   ;Close read file.
  1179.                MOV     AH,3EH
  1180.                INT     21H
  1181.                POPF                            ;Write file status.
  1182.  
  1183. COPY_END:      PUSHF                           ;Save status.
  1184.                JNC     CK_DELETE               ;If no carry, successful.
  1185.                CALL    HIDE_CURSOR
  1186.                CALL    MENU_OFFSET             ;Else, calculate menu offset.
  1187.                ADD     DI,80 * 2               ;Place error message on second
  1188.                MOV     BH,MENU_ATTR            ; menu line with menu
  1189.                MOV     SI,RESPONSE             ; attribute.
  1190.                CALL    WRITE_STRING            ;Write the message.
  1191.                MOV     SI,OFFSET PRESS_MSG
  1192.                CALL    WRITE_STRING
  1193.                CALL    BEEP                    ;Draw attention with beep.
  1194.                CALL    GET_KEY                 ;Pause for keystroke.
  1195.                JMP     SHORT COPY_RETURN
  1196.  
  1197. CK_DELETE:     CMP     RESPONSE,OFFSET MOVE_MSG  ;Move request?
  1198.                JNZ     COPY_RETURN               ;If no, done here.
  1199.                POPF
  1200.                MOV     DX,OFFSET SOURCE_FILE     ;Else, delete the source
  1201.                MOV     AH,41H                    ; file.
  1202.                INT     21H
  1203.                PUSHF
  1204.  
  1205. COPY_RETURN:   POPF                            ;Retrieve status.
  1206.                RET
  1207.  
  1208. ;----------------------------------------------;
  1209. ; INPUT: SI -> Filename;  DI -> End of path.   ;
  1210. ;----------------------------------------------;
  1211. ADD_NAME:      MOV     AL,"\"                  ;Backslash delimiter.
  1212.                CMP     [DI - 1],AL             ;Is there a delimiter?
  1213.                JZ      ADD_IT                  ;If yes, continue.
  1214.                STOSB                           ;Else, add delimiter.
  1215. ADD_IT:        LODSB                           ;Add the filename.
  1216.                CMP     AL,"a"
  1217.                JB      GOT_NAME
  1218.                CMP     AL,"z"
  1219.                JA      GOT_NAME
  1220.                AND     AL,5FH                  ;Capitalize.
  1221. GOT_NAME:      STOSB
  1222.                OR      AL,AL                   ;ASCIIZ.
  1223.                JNZ     ADD_IT
  1224.                RET
  1225.  
  1226. ;----------------------------------------------;
  1227. F6:            PUSH    DS                      ;Preserve segment registers.
  1228.                PUSH    ES                      ;Place cursor back on screen at
  1229.                MOV     DX,300H                 ; third row in case there is
  1230.                CALL    SET_CURSOR              ; a DOS print error message.
  1231.                MOV     BX,SOURCE_SEG           ;BX -> source segment.
  1232.                XOR     SI,SI                   ;Start of source.
  1233.                XOR     DI,DI                   ;Start of target.
  1234.                XOR     BP,BP                   ;Start of order.
  1235.                JMP     SHORT PRINT_HEADER      ;Print directory header on
  1236.                                                ; page.
  1237.  
  1238. NEXT_PRINT:    MOV     DS,BX                   ;Source on left side of page.
  1239.                CMP     LIST_NAME[SI],-1        ;End of listing?
  1240.                JNZ     PRINT1                  ;If no, continue.
  1241.                MOV     DS,CS:TARGET_SEG        ;Target listing segment
  1242.                CMP     LIST_NAME[DI],-1        ;End of Target listing also?
  1243.                JZ      F6_END                  ;If yes, done.
  1244.  
  1245. PRINT1:        MOV     DS,BX                   ;Source segment.
  1246.                MOV     CX,40                   ;40 characters per half line.
  1247.                CALL    DO_LINE                 ;Print a spec.
  1248.                XCHG    SI,DI                   ;Target pointer.
  1249.                MOV     DS,CS:TARGET_SEG        ;Target segment.
  1250.                MOV     CX,40
  1251.                CALL    DO_LINE                 ;Print left half of line.
  1252.                XCHG    SI,DI                   ;Restore pointers.
  1253.                CALL    NEW_LINE                ;CR LF to new line.
  1254.                INC     BP                      ;Increment order counter.
  1255.                MOV     AX,BP
  1256.                XOR     DX,DX
  1257.                MOV     CX,54
  1258.                DIV     CX
  1259.                OR      DX,DX                   ;If MOD 54 = 0 then formfeed.
  1260.                JNZ     NEXT_PRINT
  1261.                CALL    FORMFEED
  1262. PRINT_HEADER:  PUSH    CS                      ;Back to code segment.
  1263.                POP     DS
  1264.                PUSH    SI                      ;Save some pointers.
  1265.                PUSH    BP
  1266.                MOV     BP,OFFSET PRINT_CHAR    ;Print directory heading at
  1267.                CALL    WRITE_PATH              ; top of each page.
  1268.                POP     BP                      ;Restore the pointers.
  1269.                POP     SI
  1270.                CALL    NEW_LINE                ;Double space before filenames.
  1271.                CALL    NEW_LINE
  1272.                JMP     NEXT_PRINT              ;Next line.
  1273.  
  1274. F6_END:        CALL    FORMFEED                ;Spit out last printed page.
  1275.                CALL    HIDE_CURSOR
  1276.                POP     ES                      ;Restore segments.
  1277.                POP     DS
  1278.                RET
  1279.  
  1280. ;----------------------------------------------------;
  1281. ; INPUT: DS:SI -> filename.  Entry point at DO_LINE  ;
  1282. ;----------------------------------------------------;
  1283. NEXT_REC2:     ADD     SI,SIZE FILE_RECORD     ;Next filename.
  1284. DO_LINE:       CMP     LIST_NAME[SI],-1        ;Last record?
  1285.                JZ      BLANK_LINE              ;If yes, blank line.
  1286.                MOV     DX,DISP_ORDER[SI]       ;Retrieve display order.
  1287.                CMP     DX,-1                   ;Is it displayed?
  1288.                JZ      NEXT_REC2               ;If no, next record.
  1289.                MOV     AX,OFFSET NOT_RECENT    ;Assume not a recent file.
  1290.                TEST    DX,8000H                ;Is it highlighted?
  1291.                JZ      COMPARE_PRINT           ;If no, see if current order.
  1292.                MOV     AX,OFFSET RECENT        ;Else, use recent codes.
  1293.                AND     DX,NOT 8000H            ;Strip highlight bit.
  1294. COMPARE_PRINT: CMP     DX,BP                   ;Entry less than order?
  1295.                JB      NEXT_REC2               ;If yes, next record.
  1296.                JA      BLANK_LINE              ;If above, blank line.
  1297.                PUSH    BX
  1298.                PUSH    CX
  1299.                MOV     BX,AX                   ;Get offset.
  1300.                MOV     AL,CS:[BX]              ;Get char or code count.
  1301.                CMP     AL,6                    ;Is it above 6?
  1302.                JA      PRINT_MARK              ;If yes, assumed right.
  1303.                MOV     CL,AL                   ;Else, it's a printer code
  1304.                                                ; count.
  1305.                XOR     CH,CH                   ;Zero in high half.
  1306. NEXT_CODE:     INC     BX                      ;Point to a code.
  1307.                MOV     AL,CS:[BX]              ;Retrieve it.
  1308.                CALL    PRINT_CHAR              ;Print it.
  1309.                LOOP    NEXT_CODE
  1310.                MOV     AL,SPACE                ;Indent with a space.
  1311. PRINT_MARK:    CALL    PRINT_CHAR
  1312.                POP     CX
  1313.                POP     BX
  1314.                DEC     CX
  1315. PRINT_LINE:    LODSB                           ;Else, print the line.
  1316.                CALL    PRINT_CHAR
  1317.                LOOP    PRINT_LINE
  1318.                ADD     SI,7                    ;Pointer date/time/order
  1319.                JMP     SHORT DO_LINE_END       ; fields.
  1320. BLANK_LINE:    MOV     AL,SPACE                ;Blank line with spaces.
  1321.                CALL    PRINT_CHAR
  1322.                LOOP    BLANK_LINE
  1323. DO_LINE_END:   RET
  1324.  
  1325. ;----------------------------------------------;
  1326. NEW_LINE:      MOV     AL,CR                   ;Carriage return linefeed.
  1327.                CALL    PRINT_CHAR
  1328.                MOV     AL,LF
  1329.                CALL    PRINT_CHAR
  1330.                RET
  1331.  
  1332. FORMFEED:      MOV     AL,FF                   ;Formfeed.
  1333.  
  1334. PRINT_CHAR:    MOV     DL,AL                   ;Print via DOS.
  1335.                MOV     AH,5
  1336.                INT     21H
  1337.                RET
  1338.  
  1339. ;-----------------------------------------------------------------------;
  1340. ; OUTPUT: DS:SI -> Highlighted bar record; CY = 1 if bar on blank line. ;
  1341. ;-----------------------------------------------------------------------;
  1342. FIND_BAR:      MOV     DI,BAR_LINE             ;Retrieve bar line.
  1343.                XOR     SI,SI                   ;DS:SI -> source records.
  1344.                MOV     DS,SOURCE_SEG
  1345.                JMP     SHORT GET_BAR
  1346. NEXT_BAR:      ADD     SI,SIZE FILE_RECORD     ;Next record.
  1347. GET_BAR:       CMP     LIST_NAME[SI],-1        ;End of listing?
  1348.                JZ      NO_NAME                 ;If yes, no name.
  1349.                MOV     BX,DISP_ORDER[SI]       ;Retrieve display order.
  1350.                CMP     BX,-1                   ;Is it displayed?
  1351.                JZ      NEXT_BAR                ;If no, next record.
  1352.                AND     BX,NOT 8000H            ;Else, strip highlight bit.
  1353.                CMP     BX,DI                   ;Is display order same as bar?
  1354.                JB      NEXT_BAR                ;If > then next record.
  1355.                JA      NO_NAME                 ;If above, then no name.
  1356.                CLC                             ;If same, then valid name.
  1357.                RET
  1358.  
  1359. NO_NAME:       STC
  1360.                RET
  1361.  
  1362. ;-----------------------------------------------------------------;
  1363. ; INPUT: CX = binary count; OUTPUT: SOURCE_NAME = ASCII of count. ;
  1364. ;-----------------------------------------------------------------;
  1365. GET_COUNT:     PUSH    BX
  1366.                PUSH    DI
  1367.                MOV     AX,CX                   ;Retrieve number.
  1368.                MOV     BX,10                   ;Divisor of ten.
  1369.                XOR     CX,CX                   ;Zero in counter.
  1370. NEXT_DIV:      XOR     DX,DX                   ;Zero in high half.
  1371.                DIV     BX                      ;Divide by ten.
  1372.                ADD     DL,"0"                  ;Convert to ASCII.
  1373.                PUSH    DX                      ;Save results.
  1374.                INC     CX                      ;Also increment count.
  1375.                OR      AX,AX                   ;Are we done?
  1376.                JNZ     NEXT_DIV                ;Continue until zero.
  1377.  
  1378.                MOV     DI,OFFSET SOURCE_NAME
  1379. NEXT_NUMBER:   POP     AX                      ;Retrieve numbers.
  1380.                STOSB                           ;And store.
  1381.                LOOP    NEXT_NUMBER
  1382.                XOR     AL,AL                   ;ASCIIZ string.
  1383.                STOSB
  1384.                POP     DI
  1385.                POP     BX
  1386.                RET
  1387.  
  1388. ;--------------------------------------------------------------;
  1389. ; INPUT: BP -> Source filename; OUTPUT: SOURCE_NAME = filename ;
  1390. ;--------------------------------------------------------------;
  1391. GET_SOURCE:    PUSH    DS
  1392.                MOV     DS,SOURCE_SEG           ;DS:SI -> Source name.
  1393.                MOV     SI,BP
  1394.                MOV     DI,OFFSET SOURCE_NAME   ;Name storage.
  1395.                MOV     CX,8                    ;8 characters of name.
  1396. NEXT_NAME:     LODSB
  1397.                CMP     AL,SPACE                ;End of name?
  1398.                JZ      EXTENSION               ;If yes, do extension.
  1399.                STOSB
  1400.                LOOP    NEXT_NAME
  1401. EXTENSION:     MOV     SI,BP                   ;Retrieve name start.
  1402.                ADD     SI,9                    ;Move to extension field.
  1403.                CMP     BYTE PTR [SI],SPACE     ;Is there any extension?
  1404.                JZ      NAME_DONE               ;If no, done.
  1405.                MOV     AL,"."                  ;Else, add delimiting dot.
  1406.                STOSB
  1407.                MOV     CX,3                    ;3 characters for extension.
  1408. NEXT_EXT:      LODSB
  1409.                CMP     AL,SPACE
  1410.                JZ      NAME_DONE
  1411.                STOSB
  1412.                LOOP    NEXT_EXT
  1413. NAME_DONE:     XOR     AL,AL                   ;ASCIIZ.
  1414.                STOSB
  1415.                POP     DS
  1416.                RET
  1417.  
  1418. ;-----------------------------------------------------------------------------;
  1419. ; INPUT: BX -> MARKED_MSG if marked; OUTPUT: ZF=1 if cancel; ZF=0 if confirm. ;
  1420. ;-----------------------------------------------------------------------------;
  1421. GET_RESPONSE:  PUSH    BX                      ;Save message pointer.
  1422.                CALL    MENU_OFFSET             ;Calculate menu screen offset.
  1423.                MOV     BH,MENU_ATTR            ;Menu attribute.
  1424.                MOV     CX,80 * 2               ;Blank out the two lines of
  1425.                                                ; menu.
  1426. NEXT_MENU:     MOV     AL,SPACE
  1427.                CALL    WRITE_SCREEN
  1428.                LOOP    NEXT_MENU
  1429.                MOV     DH,ROWS                 ;Retrieve the rows.
  1430.                DEC     DH                      ;Next to last line.
  1431.                XOR     DL,DL
  1432.                CALL    SET_CURSOR              ;Set the cursor.
  1433.                MOV     SI,RESPONSE             ;Write TTY, copy or move
  1434.                CALL    TTY_STRING              ; message.
  1435.                MOV     SI,OFFSET SOURCE_NAME   ;Write filename or mark count.
  1436.                CALL    TTY_STRING
  1437.                POP     BX                      ;Retrieve message pointer.
  1438.                CMP     BX,OFFSET MARKED_MSG    ;Is it "marked files" message?
  1439.                JNZ     DO_TO                   ;If no, skip.
  1440.                MOV     SI,BX                   ;Else, display it.
  1441.                CALL    TTY_STRING
  1442. DO_TO:         MOV     SI,OFFSET TO_MSG        ;Display rest of
  1443.                CALL    TTY_STRING              ; "to Target Directory?  Y/N"
  1444.                MOV     SI,OFFSET DIRECTORY_MSG ; message.
  1445.                CALL    TTY_STRING
  1446.                MOV     SI,OFFSET QUERY_MSG
  1447.                CALL    TTY_STRING
  1448. NEXT_RESPONSE: CALL    GET_KEY                 ;Get a key.
  1449.                CMP     AL,ESC_SCAN             ;If ESC, abort.
  1450.                JZ      RESPONSE_END
  1451.                CMP     AL,N_SCAN               ;If "N", abort.
  1452.                JZ      RESPONSE_END
  1453.                CMP     AL,Y_SCAN               ;If not "Y", ignore.
  1454.                JNZ     NEXT_RESPONSE           ;Else, cursor to
  1455.                MOV     DX,300H                 ; third row in case there is
  1456.                CALL    SET_CURSOR              ; a DOS critical error message.
  1457.                OR      AL,1                    ;Return ZF = 0 to confirm.
  1458. RESPONSE_END:  RET
  1459.   
  1460. ;----------------------------------------------;
  1461. VIDEO_SETUP:   MOV     AX,500H                 ;Make sure active page is zero.
  1462.                INT     10H
  1463.                MOV     AX,40H                  ;Point to the ROM BIOS data
  1464.                MOV     ES,AX                   ; area
  1465.  
  1466.                MOV     AL,ES:CRT_MODE          ;Retrieve current video mode.
  1467.                CMP     AL,7                    ;Is it mono mode?
  1468.                JZ      GET_ROWS                ;If yes, continue.
  1469.                ADD     STATUS_REG,20H          ;Else, adjust status register
  1470.                ADD     VIDEO_SEG,800H          ; and video segment.
  1471.                CMP     AL,2                    ;Is it BW80?
  1472.                JZ      GET_ROWS                ;If yes, continue.
  1473.                MOV     HEADING_ATTR,INVERSE_BLUE
  1474.                MOV     ACTIVE_ATTR,INTENSE
  1475.                MOV     BODY_ATTR,BLUE          ;Else, use color attributes.
  1476.                MOV     HIGHLIGHT_ATTR,INTENSE_BLUE
  1477.                MOV     MENU_ATTR,INVERSE_BLUE
  1478.                MOV     BAR_ATTR,CYAN
  1479.                CMP     AL,3                    ;Is it mode CO80?
  1480.                JZ      GET_ROWS                ;If yes, continue.
  1481.                MOV     AX,300H                 ;Else, change video mode to CO80.
  1482.                INT     10H
  1483.  
  1484. GET_ROWS:      MOV     AL,ES:CRT_ROWS          ;Retrieve rows - 1.
  1485.                OR      AL,AL                   ;BIOS supported?
  1486.                JNZ     STORE_ROWS              ;If yes, store
  1487.                MOV     AL,24                   ;Else, use 25 lines.
  1488. STORE_ROWS:    MOV     ROWS,AL                 ;Store rows.
  1489.                XOR     AH,AH
  1490.                SUB     AX,4
  1491.                MOV     PAGE_LENGTH,AX          ;Page length = display rows-4.
  1492.  
  1493. ;----------------------------------------------;
  1494. DISPLAY_SETUP: PUSH    CS
  1495.                POP     ES
  1496.                CALL    CLS                     ;Clear screen.
  1497.                CALL    HIDE_CURSOR             ;Hide the cursor off screen.
  1498.  
  1499.                MOV     BL,MENU_ATTR            ;Turn on border.
  1500.                MOV     CL,4
  1501.                SHR     BL,CL
  1502.                MOV     AH,0BH
  1503.                INT     10H
  1504.  
  1505.                MOV     SI,OFFSET COPYRIGHT     ;Point to copyright message.
  1506.                XOR     DI,DI                   ;Point to top left of display.
  1507.                MOV     BH,HEADING_ATTR         ;Use header attribute.
  1508.                CALL    WRITE_STRING            ;And display it.
  1509.                MOV     AL,BOX
  1510.                CALL    WRITE_SCREEN
  1511.                MOV     AL,SPACE
  1512.                CALL    WRITE_SCREEN
  1513.                INC     SI                      ;Bump pointer past LF
  1514.                CALL    WRITE_STRING            ; and display rest of header.
  1515.                CALL    DISPLAY_DIRS            ;Display directory heading.
  1516.  
  1517.                MOV     BP,OFFSET WRITE_SCREEN  ;Display directories.
  1518.                CALL    WRITE_PATH
  1519.  
  1520.                MOV     BH,BODY_ATTR            ;Body attribute.
  1521.                MOV     CX,PAGE_LENGTH          ;Page length.
  1522.                MOV     DI,(3 * 160) + (2 * 40) ;Middle of third row.
  1523. NEXT_LINE:     MOV     AL,VERT_LINE            ;Display delimiting
  1524.                CALL    WRITE_SCREEN            ; vertical lines.
  1525.                ADD     DI,(2 * 79)
  1526.                LOOP    NEXT_LINE
  1527.  
  1528. ;----------------------------------------------;
  1529. DISPLAY_MENU:  MOV     SI,OFFSET MENU          ;Display menu on bottom two
  1530.                CALL    MENU_OFFSET             ; lines.
  1531.                MOV     CL,MENU_ATTR            ;Menu attribute.
  1532.                MOV     CH,ACTIVE_ATTR          ;Active mode attribute.
  1533.  
  1534.                MOV     BH,CL
  1535.                CALL    WRITE_STRING            ;"F1"
  1536.  
  1537.                CMP     FILES_MODE,ALL
  1538.                JNZ     DISPLAY3
  1539.                MOV     BH,CH
  1540. DISPLAY3:      CALL    WRITE_STRING            ;"All files"
  1541.  
  1542.                MOV     BH,CL
  1543.                CMP     FILES_MODE,UNIQUE
  1544.                JNZ     DISPLAY4
  1545.                MOV     BH,CH
  1546. DISPLAY4:      CALL    WRITE_STRING            ;"Different files"
  1547.  
  1548.                MOV     BH,CL
  1549.                CMP     FILES_MODE,ALIKE
  1550.                JNZ     DISPLAY5
  1551.                MOV     BH,CH
  1552. DISPLAY5:      CALL    WRITE_STRING            ;"Alike files"
  1553.  
  1554.                MOV     BH,CL
  1555.                CALL    WRITE_STRING            ;Print rest of menu
  1556.                RET
  1557.  
  1558. ;----------------------------------------------;
  1559. DISPLAY_DIRS:  MOV     BH,ACTIVE_ATTR          ;Directory attribute.
  1560.                MOV     DI,80 * 2
  1561.                MOV     SI,OFFSET SOURCE_MSG    ;Display "Source Directory"
  1562.                CALL    WRITE_STRING
  1563.                CALL    WRITE_STRING
  1564.                MOV     CX,SOURCE_COUNT
  1565.                CALL    WRITE_COUNT             ;Write the source file count.
  1566.                MOV     SI,OFFSET TARGET_MSG    ;Display "Target Directory".
  1567.                CALL    WRITE_STRING
  1568.                MOV     SI,OFFSET DIRECTORY_MSG
  1569.                CALL    WRITE_STRING
  1570.                MOV     CX,TARGET_COUNT         ;And finally target files
  1571.                                                ; count.
  1572.  
  1573. WRITE_COUNT:   CALL    GET_COUNT
  1574.                MOV     CX,GAP
  1575. NEXT_GAP:      MOV     AL,SPACE                ;Space over some.
  1576.                CALL    WRITE_SCREEN
  1577.                LOOP    NEXT_GAP
  1578.                MOV     SI,OFFSET SOURCE_NAME   ;Storage for count in ASCIIZ.
  1579.                MOV     CX,40 - DIRECTORY_LEN
  1580. NEXT_NUM:      LODSB                           ;Get a number.
  1581.                OR      AL,AL                   ;End of string?
  1582.                JZ      WRITE_FILES             ;If yes, add "files" message.
  1583.                CALL    WRITE_SCREEN
  1584.                LOOP    NEXT_NUM
  1585. WRITE_FILES:   MOV     SI,OFFSET FILES_MSG
  1586.                CALL    WRITE_STRING
  1587. NEXT_SPACE:    MOV     AL,SPACE                ;Pad balance with spaces.
  1588.                CALL    WRITE_SCREEN
  1589.                LOOP    NEXT_SPACE
  1590.                RET
  1591.  
  1592. ;----------------------------------------;
  1593. ; OUTPUT: DI -> Screen offset for menu.  ;
  1594. ;----------------------------------------;
  1595. MENU_OFFSET:   MOV     AL,2 * 80               ;(Rows * chars) - chars
  1596.                MUL     ROWS                    ; = menu offset.
  1597.                SUB     AX,2 * 80
  1598.                MOV     DI,AX
  1599.                RET
  1600.  
  1601. ;-----------------------------------------------------------------------------;
  1602. ; INPUT: SI->Filespec; DI->Video buffer; BP=OFFSET WRITE_SCREEN OR PRINT_CHAR;
  1603. ;-----------------------------------------------------------------------------;
  1604. WRITE_PATH:    MOV     SI,OFFSET SOURCE_SPEC   ;Write first string.
  1605.                CALL    DISP_FILESPEC
  1606.                MOV     SI,OFFSET TARGET_SPEC   ;Write second string.
  1607.  
  1608. DISP_FILESPEC: MOV     AL,SPACE                ;Indent one space.
  1609.                CALL    BP
  1610.                MOV     CX,39
  1611. NEXT_FILESPEC: LODSB
  1612.                OR      AL,AL                   ;Null terminates string.
  1613.                JZ      PAD_SPACES              ;Pad balance with spaces.
  1614.                CALL    BP
  1615.                LOOP    NEXT_FILESPEC
  1616.                JMP     SHORT FILESPEC_END
  1617. PAD_SPACES:    MOV     AL,SPACE
  1618.                CALL    BP
  1619.                LOOP    PAD_SPACES
  1620. FILESPEC_END:  RET
  1621.  
  1622. ;----------------------------------------------------;
  1623. ; INPUT:  AL = character to write;  BH = attribute.  ;
  1624. ;----------------------------------------------------;
  1625. WRITE_SCREEN:  PUSH    ES
  1626.                MOV     ES,CS:VIDEO_SEG         ;Point to screen segment.
  1627.                MOV     DX,CS:STATUS_REG        ;Retrieve status register.
  1628.                MOV     BL,AL                   ;Store character in BL.
  1629.  
  1630. HORZ_RET:      IN      AL,DX                   ;Get status.
  1631.                RCR     AL,1                    ;Is it low?
  1632.                JC      HORZ_RET                ;If not, wait until it is.
  1633.                CLI                             ;No more interrupts.
  1634.  
  1635. HWAIT:         IN      AL,DX                   ;Get status.
  1636.                RCR     AL,1                    ;Is it high?
  1637.                JNC     HWAIT                   ;If no, wait until it is.
  1638.  
  1639.                MOV     AX,BX                   ;Retrieve character; now it's
  1640.                STOSW                           ; OK to write to screen buffer.
  1641.                STI                             ;Interrupts back on.
  1642.                POP     ES
  1643.                RET                             ;Return
  1644.  
  1645. ;------------------------------------------------------------------;
  1646. ; INPUT:  SI -> to string to display;  DI -> where to display it.  ;
  1647. ;   Entry point is WRITE_STRING.                                   ;
  1648. ;------------------------------------------------------------------;
  1649. WRITE_IT:      CALL    WRITE_SCREEN            ;Write a character.
  1650. WRITE_STRING:  LODSB                           ;Retrieve a character.
  1651.                CMP     AL,CR                   ;Keep writing until a carriage
  1652.                JA      WRITE_IT                ; return or zero encountered.
  1653.                RET
  1654.  
  1655. ;----------------------------------------------;
  1656. STORE_NAME:    MOV     SI,OFFSET DTA.FILE_NAME ;Point to filename.
  1657.                PUSH    DI
  1658.                MOV     AX,SPACE SHL 8 + SPACE  ;Initiate storage with spaces.
  1659.                MOV     CX,(SIZE FILE_RECORD - 6) / 2   ;Fill out with spaces.
  1660.                REP     STOSW
  1661.                POP     DI                      ;Point to start of storage
  1662.                                                ; again.
  1663.                MOV     CX,SIZE LIST_NAME       ;Store 12 bytes of filename.
  1664. NEXT_STORE:    LODSB                           ;Get a byte.
  1665.                OR      AL,AL                   ;End of filename?
  1666.                JZ      END_STORE               ;If yes, finish with blanks.
  1667.                CMP     AL,"."                  ;Is it the period?
  1668.                JNZ     STORE_BYTE              ;If no, store.
  1669.                SUB     CX,3                    ;Else, store 3 spaces.
  1670.                MOV     AL,SPACE
  1671.                REP     STOSB
  1672.                ADD     CX,3
  1673.                JMP     SHORT NEXT_STORE        ;Get next byte.
  1674.  
  1675. STORE_BYTE:    STOSB                           ;Store byte.
  1676.                LOOP    NEXT_STORE              ;Get next byte.
  1677. END_STORE:     MOV     AL,SPACE                ;Pad balance with spaces.
  1678.                REP     STOSB
  1679.  
  1680.                PUSH    DI                      ;Save pointer.
  1681.                ADD     DI,8                    ;Move to end of bytes field.
  1682.                MOV     DX,DTA.SIZE_LOW         ;Retrieve high and low words
  1683.                MOV     AX,DTA.SIZE_HIGH        ; of size in bytes.
  1684.                MOV     BX,10                   ;Convert to decimal.
  1685.                STD                             ;Reverse direction.
  1686.  
  1687. NEXT_SIZE:     MOV     CX,DX                   ;Low word in CX.
  1688.                XOR     DX,DX                   ;Zero in high half.
  1689.                DIV     BX                      ;Convert to decimal.
  1690.                XCHG    AX,CX                   ;Retrieve low word.
  1691.                DIV     BX
  1692.                XCHG    AX,DX                   ;Retrieve remainder.
  1693.                ADD     AL,"0"                  ;Convert to ASCII.
  1694.                STOSB                           ;Store it.
  1695.                MOV     AX,CX                   ;Are we done?
  1696.                OR      CX,DX
  1697.                JNZ     NEXT_SIZE               ;If no, divide again.
  1698.  
  1699.                CLD                             ;Back to forward direction.
  1700.                POP     DI                      ;Retrieve pointer.
  1701.                ADD     DI,11                   ;Move to date field.
  1702. DATE:          MOV     DX,DTA.FILE_DATE        ;Retrieve date.
  1703.                MOV     AX,DX
  1704.                MOV     CL,5                    ;Shift to lowest bits.
  1705.                SHR     AX,CL
  1706.                AND     AX,1111B                ;Mask off all but month.
  1707.                MOV     CL,0FFH                 ;Flag as no leading zeros.
  1708.                MOV     CH,"-"                  ;Delimiting character.
  1709.                CALL    STORE_WORD              ;Store it.
  1710.  
  1711.                MOV     AX,DX                   ;Retrieve date.
  1712.                AND     AX,11111B               ;Mask off all but day.
  1713.                XOR     CL,CL                   ;Flag include leading zeros.
  1714.                MOV     CH,"-"
  1715.                CALL    STORE_WORD              ;Store it.
  1716.  
  1717.                MOV     AX,DX                   ;Retrieve date for last time.
  1718.                MOV     CL,9
  1719.                SHR     AX,CL                   ;Mask off all but year.
  1720.                ADD     AX,80                   ;Adjust to ASCII.
  1721.                CMP     AX,100                  ;Past year 2000?
  1722.                JB      DISPLAY_DATE            ;If no, display. Else, adjust
  1723.                SUB     AX,100                  ; for next century. (Planning
  1724.                                                ; ahead!)
  1725. DISPLAY_DATE:  XOR     CL,CL                   ;Display leading zeros.
  1726.                MOV     CH,SPACE
  1727.                CALL    STORE_WORD              ;Store it.
  1728.  
  1729. TIME:          INC     DI                      ;Move to time field.
  1730.                MOV     DX,DTA.FILE_TIME        ;Retrieve time.
  1731.                MOV     AX,DX
  1732.                MOV     CL,11                   ;Shift to hours bits.
  1733.                SHR     AX,CL
  1734.                PUSH    AX
  1735.                CMP     AX,12                   ;Past noon?
  1736.                JBE     MERIDIAN
  1737.                SUB     AX,12                   ;If yes, adjust.
  1738. MERIDIAN:      CMP     AX,0                    ;Midnight?
  1739.                JNZ     NOT_MIDNIGHT
  1740.                MOV     AX,12                   ;If yes, adjust.
  1741. NOT_MIDNIGHT:  MOV     CL,0FFH                 ;Suppress leading zeros.
  1742.                MOV     CH,":"
  1743.                CALL    STORE_WORD              ;Store it.
  1744.  
  1745.                MOV     AX,DX                   ;Retrieve time.
  1746.                MOV     CL,5                    ;Shift to minutes bits.
  1747.                SHR     AX,CL
  1748.                AND     AX,111111B              ;Mask off all but minutes.
  1749.                XOR     CL,CL
  1750.                POP     DX                      ;Retrieve hours.
  1751.                MOV     CH,"p"                  ;Assume PM.
  1752.                CMP     DX,12                   ;Is it PM?
  1753.                JAE     PM
  1754.                MOV     CH,"a"                  ;If no, AM.
  1755.  
  1756. PM:            CALL    STORE_WORD              ;Store it.
  1757.                INC     DI                      ;Pointer past mark.
  1758.                MOV     AX,DTA.FILE_DATE
  1759.                STOSW                           ;Store date in DOS format.
  1760.                MOV     AX,DTA.FILE_TIME
  1761.                STOSW                           ;Store time in DOS format.
  1762.                INC     DI                      ;Bump pointer past DISP_ORDER.
  1763.                INC     DI
  1764.                RET                             ;Done here.
  1765.  
  1766. ;-----------------------------------------------------------------------;
  1767. ; Converts a two byte hex number to decimal followed by delimiter.      ;
  1768. ; INPUT: AX = hex number; BL = 10; CH = delimiter character to store.   ;
  1769. ;   CL = 0 if zeros are to be stored; CL = -1 if leading zeros ignored. ;
  1770. ;   ES:DI points to storage.                                            ;
  1771. ;-----------------------------------------------------------------------;
  1772. STORE_WORD:    DIV     BL                      ;Divide by ten.
  1773.                ADD     AX,"00"                 ;Convert to ASCII.
  1774.                CMP     CL,0                    ;Display leading zero?
  1775.                JZ      STORE_IT                ;If yes, store as is.
  1776.                CMP     AL,"0"                  ;Is it a leading zero?
  1777.                JNZ     STORE_IT                ;If no, store it.
  1778.                MOV     AL,SPACE                ;Else, store a space.
  1779. STORE_IT:      STOSW
  1780.                MOV     AL,CH                   ;Also store delimiter character
  1781.                STOSB
  1782.                RET
  1783.  
  1784. ;----------------------------------------------;
  1785. CLS:           XOR     CX,CX                   ;Top left corner.
  1786.                MOV     DH,ROWS
  1787.                MOV     DL,80 - 1
  1788.                MOV     BH,BODY_ATTR            ;Normal attribute.
  1789.                MOV     AX,600H                 ;Scroll active page.
  1790.                INT     10H
  1791.                RET
  1792.  
  1793. ;----------------------------------------------;
  1794. GET_DIR:       MOV     BYTE PTR [SI],"\"       ;DOS doesn't preface directory
  1795.                INC     SI                      ; with slash so we must.
  1796.                XOR     DL,DL
  1797.                MOV     AH,47H                  ;Get current directory.
  1798.                INT     21H
  1799.                RET
  1800.  
  1801. CHANGE_DIR:    MOV     AH,3BH                  ;Change current directory.
  1802.                INT     21H
  1803.                RET
  1804.  
  1805. ;----------------------------------------------;
  1806. FIND_FIRST:    XOR     CX,CX                   ;Normal files.
  1807.                MOV     AH,4EH                  ;Find first.
  1808.                INT     21H
  1809.                RET
  1810.  
  1811. ;----------------------------------------------;
  1812. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  1813.                INT     21H
  1814.                RET
  1815.  
  1816. ;----------------------------------------------;
  1817. DISK_FREE:     MOV     DL,BYTE PTR TARGET_SPEC ;Target drive.
  1818.                SUB     DL,"A" - 1
  1819.                MOV     AH,36H                  ;Disk free space.
  1820.                INT     21H
  1821.                XOR     DX,DX
  1822.                MUL     BX                      ;Sectors per cluster * clusters
  1823.                MUL     CX                      ;Result times bytes per cluster
  1824.                RET                             ; = available bytes.
  1825.  
  1826. ;----------------------------------------------;
  1827. BEEP:          MOV     BX,NOTE                 ;Tone frequency divisor.
  1828.                MOV     DX,12H
  1829.                XOR     AX,AX
  1830.                DIV     BX
  1831.                MOV     BX,AX                   ;8253 countdown.
  1832.  
  1833.                CALL    DELAY                   ;Wait till clock rolls over.
  1834.  
  1835.                MOV     AL,0B6H                 ;Channel 2 speaker functions.
  1836.                OUT     43H,AL                  ;8253 Mode Control.
  1837.                JMP     $+2                     ;IO delay.
  1838.                MOV     AX,BX                   ;Retrieve countdown.
  1839.                OUT     42H,AL                  ;Channel 2 LSB.
  1840.                JMP     $+2
  1841.                MOV     AL,AH                   ;Channel 2 MSB.
  1842.                OUT     42H,AL
  1843.                IN      AL,61H                  ;Port B.
  1844.                OR      AL,3                    ;Turn on speaker.
  1845.                JMP     $+2
  1846.                OUT     61H,AL
  1847.  
  1848.                CALL    DELAY                   ;Delay one second.
  1849.                IN      AL,61H                  ;Get Port B again.
  1850.                AND     AL,NOT 3                ;Turn speaker off.
  1851.                JMP     $+2
  1852.                OUT     61H,AL
  1853.                RET                             ;Done.
  1854.  
  1855. ;-----------------------------;
  1856. DELAY:         PUSH    DS                      ;Preserve data segment.
  1857.                MOV     AX,40H                  ;Point to BIOS data segment.
  1858.                MOV     DS,AX
  1859.                MOV     AX,DS:[6CH]             ;Retrieve timer low.
  1860. NEXT_BEEP:     MOV     DX,DS:[6CH]             ;Retrieve timer low.
  1861.                CMP     DX,AX                   ;Have we timed out?
  1862.                JZ      NEXT_BEEP               ;If not, wait until second up.
  1863.                POP     DS                      ;Restore data segment.
  1864.                RET
  1865.  
  1866. ;----------------------------------------------;
  1867. HIDE_CURSOR:   MOV     DH,ROWS                 ;Retrieve CRT rows.
  1868.                INC     DH                      ;Move one line below off
  1869.                                                ; screen.
  1870.                XOR     DL,DL                   ;Column zero.
  1871.  
  1872. SET_CURSOR:    XOR     BH,BH                   ;Page zero.
  1873.                MOV     AH,2                    ;Set cursor position.
  1874.                INT     10H
  1875.                RET
  1876.  
  1877. ;----------------------------------------------;
  1878. GET_KEY:       MOV     AH,0                    ;Wait for next keyboard input.
  1879.                INT     16H
  1880.                XCHG    AH,AL
  1881.                RET
  1882.  
  1883. CK_KEY:        MOV     AH,1                    ;Is a keystroke available.
  1884.                INT     16H
  1885.                RET
  1886.  
  1887. CLEAR_IT:      CALL    GET_KEY                 ;Read keystrokes until buffer
  1888. CLEAR_KEY:     CALL    CK_KEY                  ; empty.
  1889.                JNZ     CLEAR_IT
  1890.                RET
  1891.  
  1892. ;----------------------------------------------;
  1893. WRITE_TTY:     MOV     AH,0EH
  1894.                INT     10H
  1895.                RET
  1896.  
  1897. TTY:           CALL    WRITE_TTY
  1898. TTY_STRING:    LODSB                           ;ASCIIZ marks end of string.
  1899.                OR      AL,AL
  1900.                JNZ     TTY
  1901.                RET
  1902.  
  1903. ;----------------------------------------------;
  1904. EVEN
  1905. DTA            =  $
  1906. SOURCE_STATS   =  DTA          + SIZE MATCHING
  1907. CURRENT_DIR    =  SOURCE_STATS + SIZE MATCHING
  1908. SOURCE_SPEC    =  CURRENT_DIR  + SPEC_LENGTH
  1909. SOURCE_FILE    =  SOURCE_SPEC  + SPEC_LENGTH
  1910. TARGET_SPEC    =  SOURCE_FILE  + SPEC_LENGTH
  1911. TARGET_FILE    =  TARGET_SPEC  + SPEC_LENGTH
  1912. USER_INPUT     =  TARGET_FILE  + SPEC_LENGTH
  1913. SOURCE_NAME    =  USER_INPUT   + 14
  1914. STACK_POINTER  =  SOURCE_NAME  + 68 + 256
  1915. SOURCE_OFFSET  =  STACK_POINTER
  1916.  
  1917. _TEXT          ENDS
  1918.                END     START
  1919.